Skip to content

Commit

Permalink
feat:Add implementation for task module
Browse files Browse the repository at this point in the history
  • Loading branch information
trestinlsd committed Mar 25, 2024
1 parent 658364d commit 238b8c9
Show file tree
Hide file tree
Showing 50 changed files with 4,850 additions and 14 deletions.
31 changes: 31 additions & 0 deletions precompiles/avsTask/abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[
{
"inputs":[
{
"internalType":"uint256",
"name":"numberToBeSquared",
"type":"uint256"
},
{
"internalType":"bytes",
"name":"quorumThresholdPercentage",
"type":"bytes"
},
{
"internalType":"bytes",
"name":"quorumNumbers",
"type":"bytes"
}
],
"name":"createNewTask",
"outputs":[
{
"internalType":"bool",
"name":"success",
"type":"bool"
}
],
"stateMutability":"nonpayable",
"type":"function"
}
]
90 changes: 90 additions & 0 deletions precompiles/avsTask/avsTask.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
pragma solidity >=0.8.17 .0;

/// @dev The AVSTask contract's address.
address constant AVSTASK_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000901;

/// @dev The AVSTask contract's instance.
IAVSTask constant AVSTASK_CONTRACT = IAVSTask(
AVSTASK_PRECOMPILE_ADDRESS
);

/// @author Exocore Team
/// @title AVSTask Precompile Contract
/// @dev The interface through which solidity contracts will interact with AVSTask
/// @custom:address 0x0000000000000000000000000000000000000901
struct Task {
uint256 numberToBeSquared;
uint32 taskCreatedBlock;
// task submitter decides on the criteria for a task to be completed
// note that this does not mean the task was "correctly" answered (i.e. the number was squared correctly)
// this is for the challenge logic to verify
// task is completed (and contract will accept its TaskResponse) when each quorumNumbers specified here
// are signed by at least quorumThresholdPercentage of the operators
// note that we set the quorumThresholdPercentage to be the same for all quorumNumbers, but this could be changed
bytes quorumNumbers;
uint32 quorumThresholdPercentage;
}

struct TaskResponse {
// Can be obtained by the operator from the event NewTaskCreated.
uint32 referenceTaskIndex;
// This is just the response that the operator has to compute by itself.
uint256 numberSquared;
}

// Extra information related to taskResponse, which is filled inside the contract.
// It thus cannot be signed by operators, so we keep it in a separate struct than TaskResponse
// This metadata is needed by the challenger, so we emit it in the TaskResponded event
struct TaskResponseMetadata {
uint32 taskResponsedBlock;
bytes32 hashOfNonSigners;
}
/// @dev Represents a operator in the avs module.
struct Operator {
string earningsAddr;
string approveAddr;
string operatorMetaInfo;
}
interface IAVSTask {
/// TRANSACTIONS
/// @dev IAVSTask the oprator, that will change the state in AVSTask module
/// @param numberToBeSquared The Numbers that need to be squared
/// @param quorumThresholdPercentage The Quorum threshold
/// @param quorumNumbers The Quorum numbers
function createNewTask(
uint256 numberToBeSquared,
uint32 quorumThresholdPercentage,
bytes calldata quorumNumbers
) external returns (bool success);

/// TRANSACTIONS
/// @dev this function responds to existing tasks.
/// @param Task The task of avs already created
/// @param TaskResponse The Task response parameters
function respondToTask(
Task calldata task,
TaskResponse calldata taskResponse
) external returns (bool success);

/// TRANSACTIONS
/// @dev Get the count of the current task
function taskNumber() external view returns (uint32);

/// TRANSACTIONS
/// @dev Get the task window block for the current response
function getTaskResponseWindowBlock() external view returns (uint32);

/// TRANSACTIONS
/// @dev Get the task window block for the current response
function queryOptinOperatorList(address avsAddress) external view returns (bool success,Operator[] calldata operators);
/// @dev This event is emitted when a task created.

/// TRANSACTIONS
/// @dev Get the task window block for the current response
function queryOperatorInfoByAddr(address operatorAddress) external view returns (bool success,Operator calldata operator);

function isOperatorOptin(address operatorAddress) external view returns (bool success);

event NewTaskCreated(uint32 indexed taskIndex, Task task);

}
8 changes: 8 additions & 0 deletions precompiles/avsTask/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package task

Check failure on line 1 in precompiles/avsTask/error.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

: # github.com/ExocoreNetwork/exocore/precompiles/avsTask

const (
ErrContractInputParaOrType = "the contract input parameter type or value error,arg index:%d, type is:%s,value:%v"
ErrContractCaller = "the caller doesn't have the permission to call this function,caller:%s,need:%s"
ErrInputClientChainAddrLength = "the length of input client chain addr doesn't match,input:%d,need:%d"
ErrNotYetRegistered = "this AVS has not been registered yet,input:%d"
)
54 changes: 54 additions & 0 deletions precompiles/avsTask/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package task

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
cmn "github.com/evmos/evmos/v14/precompiles/common"
)

const (
// EventTypeNewTaskCreated defines the event type for the task create transaction.
EventTypeNewTaskCreated = "NewTaskCreated"
)

// EmitNewTaskCreatedEvent creates a new task transaction.
func (p Precompile) EmitNewTaskCreatedEvent(
ctx sdk.Context,
stateDB vm.StateDB,
taskIndex uint32,
numberToBeSquared uint64,
quorumNumbers []byte,
quorumThresholdPercentage uint32,
) error {
event := p.ABI.Events[EventTypeNewTaskCreated]
topics := make([]common.Hash, 3)

// The first topic is always the signature of the event.
topics[0] = event.ID

var err error
// sender and receiver are indexed
topics[1], err = cmn.MakeTopic(taskIndex)
if err != nil {
return err
}

// Prepare the event data: denom, amount, memo
arguments := abi.Arguments{event.Inputs[2], event.Inputs[3], event.Inputs[4]}
packed, err := arguments.Pack(numberToBeSquared, quorumNumbers, quorumThresholdPercentage)
if err != nil {
return err
}

stateDB.AddLog(&ethtypes.Log{
Address: p.Address(),
Topics: topics,
Data: packed,
BlockNumber: uint64(ctx.BlockHeight()),

Check failure

Code scanning / gosec

Potential integer overflow by integer type conversion Error

Potential integer overflow by integer type conversion
})

return nil
}
71 changes: 71 additions & 0 deletions precompiles/avsTask/methods.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package task

import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)

const (
// MethodCreateNewTask defines the ABI method name for the task
// transaction.
MethodCreateNewTask = "createNewTask"
MethodIsOperatorOptin = "isOperatorOptin"
)

// CreateNewTask Middleware uses exocore's default task template to create tasks in task module.
func (p Precompile) CreateNewTask(
ctx sdk.Context,
_ common.Address,
contract *vm.Contract,
stateDB vm.StateDB,
method *abi.Method,
args []interface{},
) ([]byte, error) {
// check the invalidation of caller contract
flag := p.avsKeeper.IsAVS(ctx, sdk.AccAddress(contract.CallerAddress.String()))
if !flag {
return nil, fmt.Errorf(ErrNotYetRegistered, contract.CallerAddress)
}

createNewTaskParams, err := p.GetTaskParamsFromInputs(ctx, args)
if err != nil {
return nil, err
}
createNewTaskParams.ContractAddr = contract.CallerAddress.String()
createNewTaskParams.TaskCreatedBlock = ctx.BlockHeight()
_, err = p.taskKeeper.CreateNewTask(ctx, createNewTaskParams)
if err != nil {
return nil, err
}
if err = p.EmitNewTaskCreatedEvent(
ctx,
stateDB,
createNewTaskParams.TaskIndex,
createNewTaskParams.NumberToBeSquared,
createNewTaskParams.QuorumNumbers,
createNewTaskParams.QuorumThresholdPercentage,
); err != nil {
return nil, err
}
return method.Outputs.Pack(true)
}

// IsOperatorOptin Middleware uses exocore's default task template to create tasks in task module.
func (p Precompile) IsOperatorOptin(
ctx sdk.Context,
contract *vm.Contract,
_ *vm.Contract,
method *abi.Method,
args []interface{},
) ([]byte, error) {
// check the invalidation of caller contract
flag := p.avsKeeper.IsAVS(ctx, sdk.AccAddress(contract.CallerAddress.String()))
if !flag {
return nil, fmt.Errorf(ErrNotYetRegistered, contract.CallerAddress)
}

return method.Outputs.Pack(true)
}
27 changes: 27 additions & 0 deletions precompiles/avsTask/parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package task

import (
"fmt"
"reflect"

Check failure

Code scanning / gosec

Blocklisted import runtime Error

Blocklisted import reflect

Check notice

Code scanning / CodeQL

Sensitive package import Note

Certain system packages contain functions which may be a possible source of non-determinism

"github.com/ExocoreNetwork/exocore/x/taskmanageravs/keeper"
sdk "github.com/cosmos/cosmos-sdk/types"
cmn "github.com/evmos/evmos/v14/precompiles/common"
)

func (p Precompile) GetTaskParamsFromInputs(ctx sdk.Context, args []interface{}) (*keeper.CreateNewTaskParams, error) {
if len(args) != 8 {
return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 4, len(args))
}
taskParams := &keeper.CreateNewTaskParams{}
numberToBeSquared, ok := args[0].(uint16)
if !ok {
return nil, fmt.Errorf(ErrContractInputParaOrType, 0, reflect.TypeOf(args[0]), numberToBeSquared)
}
taskParams.NumberToBeSquared = uint64(numberToBeSquared)
taskParams.QuorumThresholdPercentage = args[1].(uint32)
qnums, ok := args[2].([]byte)

Check warning

Code scanning / CodeQL

Useless assignment to local variable Warning

This definition of ok is never used.
taskParams.QuorumNumbers = qnums

return taskParams, nil
}
36 changes: 36 additions & 0 deletions precompiles/avsTask/setup_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package task_test

import (
"github.com/ExocoreNetwork/exocore/testutil"
"testing"

"github.com/ExocoreNetwork/exocore/precompiles/slash"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/stretchr/testify/suite"
)

var s *TaskPrecompileTestSuite

type TaskPrecompileTestSuite struct {
testutil.BaseTestSuite
precompile *slash.Precompile
}

func TestPrecompileTestSuite(t *testing.T) {
s = new(TaskPrecompileTestSuite)
suite.Run(t, s)

// Run Ginkgo integration tests
RegisterFailHandler(Fail)
RunSpecs(t, "Slash Precompile Suite")
}

func (s *TaskPrecompileTestSuite) SetupTest() {
s.DoSetupTest()
precompile, err := slash.NewPrecompile(s.App.StakingAssetsManageKeeper, s.App.ExoSlashKeeper, s.App.AuthzKeeper)
s.Require().NoError(err)
s.precompile = precompile
}
Loading

0 comments on commit 238b8c9

Please sign in to comment.