From 5a171b6f2df906150b508db24c1863f05dcc304a Mon Sep 17 00:00:00 2001 From: zhi Date: Mon, 13 Oct 2025 21:07:16 +0800 Subject: [PATCH] v4 to read candidate --- action/candidate_register.go | 10 +- action/candidate_update.go | 10 +- .../protocol/staking/ethabi/common/types.go | 5 + action/protocol/staking/ethabi/stake_base.go | 5 + action/protocol/staking/ethabi/v4/builder.go | 23 +++ .../ethabi/v4/stake_candidatebyaddress.go | 88 ++++++++++++ .../staking/ethabi/v4/stake_candidatebyid.go | 136 ++++++++++++++++++ .../ethabi/v4/stake_candidatebyname.go | 88 ++++++++++++ .../staking/ethabi/v4/stake_candidates.go | 93 ++++++++++++ .../ethabi/v4/stakecandidatebyaddress_test.go | 71 +++++++++ .../ethabi/v4/stakecandidatebyid_test.go | 71 +++++++++ .../ethabi/v4/stakecandidatebyname_test.go | 71 +++++++++ .../staking/ethabi/v4/stakecandidates_test.go | 108 ++++++++++++++ go.mod | 2 +- go.sum | 4 +- 15 files changed, 772 insertions(+), 13 deletions(-) create mode 100644 action/protocol/staking/ethabi/v4/builder.go create mode 100644 action/protocol/staking/ethabi/v4/stake_candidatebyaddress.go create mode 100644 action/protocol/staking/ethabi/v4/stake_candidatebyid.go create mode 100644 action/protocol/staking/ethabi/v4/stake_candidatebyname.go create mode 100644 action/protocol/staking/ethabi/v4/stake_candidates.go create mode 100644 action/protocol/staking/ethabi/v4/stakecandidatebyaddress_test.go create mode 100644 action/protocol/staking/ethabi/v4/stakecandidatebyid_test.go create mode 100644 action/protocol/staking/ethabi/v4/stakecandidatebyname_test.go create mode 100644 action/protocol/staking/ethabi/v4/stakecandidates_test.go diff --git a/action/candidate_register.go b/action/candidate_register.go index 947b8b5d6b..42872e4aaf 100644 --- a/action/candidate_register.go +++ b/action/candidate_register.go @@ -229,8 +229,8 @@ func (cr *CandidateRegister) Proto() *iotextypes.CandidateRegister { switch { case cr.WithBLS(): - act.Candidate.PubKey = make([]byte, len(cr.pubKey)) - copy(act.Candidate.PubKey, cr.pubKey) + act.Candidate.BlsPubKey = make([]byte, len(cr.pubKey)) + copy(act.Candidate.BlsPubKey, cr.pubKey) if cr.value != nil { act.StakedAmount = cr.value.String() } @@ -266,10 +266,10 @@ func (cr *CandidateRegister) LoadProto(pbAct *iotextypes.CandidateRegister) erro cr.duration = pbAct.GetStakedDuration() cr.autoStake = pbAct.GetAutoStake() - withBLS := len(pbAct.Candidate.GetPubKey()) > 0 + withBLS := len(pbAct.Candidate.GetBlsPubKey()) > 0 if withBLS { - cr.pubKey = make([]byte, len(pbAct.Candidate.GetPubKey())) - copy(cr.pubKey, pbAct.Candidate.GetPubKey()) + cr.pubKey = make([]byte, len(pbAct.Candidate.GetBlsPubKey())) + copy(cr.pubKey, pbAct.Candidate.GetBlsPubKey()) } if len(pbAct.GetStakedAmount()) > 0 { amount, ok := new(big.Int).SetString(pbAct.GetStakedAmount(), 10) diff --git a/action/candidate_update.go b/action/candidate_update.go index b982457307..9ca2d9b44a 100644 --- a/action/candidate_update.go +++ b/action/candidate_update.go @@ -156,8 +156,8 @@ func (cu *CandidateUpdate) Proto() *iotextypes.CandidateBasicInfo { } if len(cu.pubKey) > 0 { - act.PubKey = make([]byte, len(cu.pubKey)) - copy(act.PubKey, cu.pubKey) + act.BlsPubKey = make([]byte, len(cu.pubKey)) + copy(act.BlsPubKey, cu.pubKey) } return act } @@ -185,9 +185,9 @@ func (cu *CandidateUpdate) LoadProto(pbAct *iotextypes.CandidateBasicInfo) error } cu.rewardAddress = rewardAddr } - if len(pbAct.GetPubKey()) > 0 { - cu.pubKey = make([]byte, len(pbAct.GetPubKey())) - copy(cu.pubKey, pbAct.GetPubKey()) + if len(pbAct.GetBlsPubKey()) > 0 { + cu.pubKey = make([]byte, len(pbAct.GetBlsPubKey())) + copy(cu.pubKey, pbAct.GetBlsPubKey()) } return nil } diff --git a/action/protocol/staking/ethabi/common/types.go b/action/protocol/staking/ethabi/common/types.go index 1fa76ce7c9..a085dfb4a1 100644 --- a/action/protocol/staking/ethabi/common/types.go +++ b/action/protocol/staking/ethabi/common/types.go @@ -47,6 +47,7 @@ type ( TotalWeightedVotes *big.Int SelfStakeBucketIdx uint64 SelfStakingTokens *big.Int + BlsPubKey []byte } ) @@ -138,6 +139,10 @@ func EncodeCandidateToEth(candidate *iotextypes.CandidateV2) (*CandidateEth, err return nil, err } result.Id = addr + if len(candidate.BlsPubKey) > 0 { + result.BlsPubKey = make([]byte, len(candidate.BlsPubKey)) + copy(result.BlsPubKey, candidate.BlsPubKey) + } return result, nil } diff --git a/action/protocol/staking/ethabi/stake_base.go b/action/protocol/staking/ethabi/stake_base.go index 0e2f4bb3dc..09549e2fa9 100644 --- a/action/protocol/staking/ethabi/stake_base.go +++ b/action/protocol/staking/ethabi/stake_base.go @@ -6,6 +6,7 @@ import ( v1 "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/v1" v2 "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/v2" v3 "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/v3" + v4 "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/v4" ) // BuildReadStateRequest decode eth_call data to StateContext @@ -26,5 +27,9 @@ func BuildReadStateRequest(data []byte) (protocol.StateContext, error) { if err == nil { return methodSig, nil } + methodSig, err = v4.BuildReadStateRequest(data) + if err == nil { + return methodSig, nil + } return nil, stakingComm.ErrInvalidCallSig } diff --git a/action/protocol/staking/ethabi/v4/builder.go b/action/protocol/staking/ethabi/v4/builder.go new file mode 100644 index 0000000000..3dd0d8ce50 --- /dev/null +++ b/action/protocol/staking/ethabi/v4/builder.go @@ -0,0 +1,23 @@ +package v4 + +import ( + "encoding/hex" + + "github.com/iotexproject/iotex-core/v2/action/protocol" + stakingComm "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/common" +) + +func BuildReadStateRequest(data []byte) (protocol.StateContext, error) { + switch methodSig := hex.EncodeToString(data[:4]); methodSig { + case hex.EncodeToString(_candidatesMethod.ID): + return newCandidatesStateContext(data[4:]) + case hex.EncodeToString(_candidateByNameMethod.ID): + return newCandidateByNameStateContext(data[4:]) + case hex.EncodeToString(_candidateByAddressMethod.ID): + return newCandidateByAddressStateContext(data[4:]) + case hex.EncodeToString(_candidateByIDMethod.ID): + return newCandidateByIDStateContext(data[4:]) + default: + return nil, stakingComm.ErrInvalidCallSig + } +} diff --git a/action/protocol/staking/ethabi/v4/stake_candidatebyaddress.go b/action/protocol/staking/ethabi/v4/stake_candidatebyaddress.go new file mode 100644 index 0000000000..84a4e45388 --- /dev/null +++ b/action/protocol/staking/ethabi/v4/stake_candidatebyaddress.go @@ -0,0 +1,88 @@ +package v4 + +import ( + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + + "github.com/iotexproject/iotex-core/v2/action/protocol/abiutil" + stakingComm "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/common" +) + +const _candidateByAddressInterfaceABI = `[ + { + "inputs": [ + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + } + ], + "name": "candidateByAddressV4", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "operatorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "rewardAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint256", + "name": "totalWeightedVotes", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "selfStakeBucketIdx", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "selfStakingTokens", + "type": "uint256" + }, + { + "internalType": "address", + "name": "id", + "type": "address" + }, + { + "internalType": "bytes", + "name": "blsPubKey", + "type": "bytes" + } + ], + "internalType": "struct IStaking.CandidateV4", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + } +]` + +var _candidateByAddressMethod abi.Method + +func init() { + _candidateByAddressMethod = abiutil.MustLoadMethod(_candidateByAddressInterfaceABI, "candidateByAddressV4") +} + +func newCandidateByAddressStateContext(data []byte) (*stakingComm.CandidateByAddressStateContext, error) { + return stakingComm.NewCandidateByAddressStateContext(data, &_candidateByAddressMethod, iotexapi.ReadStakingDataMethod_CANDIDATE_BY_ADDRESS) +} diff --git a/action/protocol/staking/ethabi/v4/stake_candidatebyid.go b/action/protocol/staking/ethabi/v4/stake_candidatebyid.go new file mode 100644 index 0000000000..2193a00178 --- /dev/null +++ b/action/protocol/staking/ethabi/v4/stake_candidatebyid.go @@ -0,0 +1,136 @@ +package v4 + +import ( + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "google.golang.org/protobuf/proto" + + "github.com/iotexproject/iotex-core/v2/action/protocol" + "github.com/iotexproject/iotex-core/v2/action/protocol/abiutil" + stakingComm "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/common" +) + +const _candidateByIDInterfaceABI = `[ + { + "inputs": [ + { + "internalType": "address", + "name": "id", + "type": "address" + } + ], + "name": "candidateByIDV4", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "operatorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "rewardAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint256", + "name": "totalWeightedVotes", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "selfStakeBucketIdx", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "selfStakingTokens", + "type": "uint256" + }, + { + "internalType": "address", + "name": "id", + "type": "address" + }, + { + "internalType": "bytes", + "name": "blsPubKey", + "type": "bytes" + } + ], + "internalType": "struct IStaking.CandidateV4", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + } +]` + +var _candidateByIDMethod abi.Method + +func init() { + _candidateByIDMethod = abiutil.MustLoadMethod(_candidateByIDInterfaceABI, "candidateByIDV4") +} + +func newCandidateByIDStateContext(data []byte) (*stakingComm.CandidateByAddressStateContext, error) { + return NewCandidateByIDStateContext(data, &_candidateByIDMethod, iotexapi.ReadStakingDataMethod_CANDIDATE_BY_ADDRESS) +} + +func NewCandidateByIDStateContext(data []byte, methodABI *abi.Method, apiMethod iotexapi.ReadStakingDataMethod_Name) (*stakingComm.CandidateByAddressStateContext, error) { + paramsMap := map[string]interface{}{} + ok := false + if err := methodABI.Inputs.UnpackIntoMap(paramsMap, data); err != nil { + return nil, err + } + var idAddress common.Address + if idAddress, ok = paramsMap["id"].(common.Address); !ok { + return nil, stakingComm.ErrDecodeFailure + } + id, err := address.FromBytes(idAddress[:]) + if err != nil { + return nil, err + } + + method := &iotexapi.ReadStakingDataMethod{ + Method: apiMethod, + } + methodBytes, err := proto.Marshal(method) + if err != nil { + return nil, err + } + arguments := &iotexapi.ReadStakingDataRequest{ + Request: &iotexapi.ReadStakingDataRequest_CandidateByAddress_{ + CandidateByAddress: &iotexapi.ReadStakingDataRequest_CandidateByAddress{ + Id: id.String(), + }, + }, + } + argumentsBytes, err := proto.Marshal(arguments) + if err != nil { + return nil, err + } + return &stakingComm.CandidateByAddressStateContext{ + BaseStateContext: &protocol.BaseStateContext{ + Parameter: &protocol.Parameters{ + MethodName: methodBytes, + Arguments: [][]byte{argumentsBytes}, + }, + Method: methodABI, + }, + }, nil +} diff --git a/action/protocol/staking/ethabi/v4/stake_candidatebyname.go b/action/protocol/staking/ethabi/v4/stake_candidatebyname.go new file mode 100644 index 0000000000..372497c267 --- /dev/null +++ b/action/protocol/staking/ethabi/v4/stake_candidatebyname.go @@ -0,0 +1,88 @@ +package v4 + +import ( + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + + "github.com/iotexproject/iotex-core/v2/action/protocol/abiutil" + stakingComm "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/common" +) + +const _candidateByNameInterfaceABI = `[ + { + "inputs": [ + { + "internalType": "string", + "name": "candName", + "type": "string" + } + ], + "name": "candidateByNameV4", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "operatorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "rewardAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint256", + "name": "totalWeightedVotes", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "selfStakeBucketIdx", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "selfStakingTokens", + "type": "uint256" + }, + { + "internalType": "address", + "name": "id", + "type": "address" + }, + { + "internalType": "bytes", + "name": "blsPubKey", + "type": "bytes" + } + ], + "internalType": "struct IStaking.CandidateV4", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + } +]` + +var _candidateByNameMethod abi.Method + +func init() { + _candidateByNameMethod = abiutil.MustLoadMethod(_candidateByNameInterfaceABI, "candidateByNameV4") +} + +func newCandidateByNameStateContext(data []byte) (*stakingComm.CandidateByNameStateContext, error) { + return stakingComm.NewCandidateByNameStateContext(data, &_candidateByNameMethod, iotexapi.ReadStakingDataMethod_CANDIDATE_BY_NAME) +} diff --git a/action/protocol/staking/ethabi/v4/stake_candidates.go b/action/protocol/staking/ethabi/v4/stake_candidates.go new file mode 100644 index 0000000000..371613ed8d --- /dev/null +++ b/action/protocol/staking/ethabi/v4/stake_candidates.go @@ -0,0 +1,93 @@ +package v4 + +import ( + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + + "github.com/iotexproject/iotex-core/v2/action/protocol/abiutil" + stakingComm "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/common" +) + +const _candidatesInterfaceABI = `[ + { + "inputs": [ + { + "internalType": "uint32", + "name": "offset", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "limit", + "type": "uint32" + } + ], + "name": "candidatesV4", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "operatorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "rewardAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint256", + "name": "totalWeightedVotes", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "selfStakeBucketIdx", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "selfStakingTokens", + "type": "uint256" + }, + { + "internalType": "address", + "name": "id", + "type": "address" + }, + { + "internalType": "bytes", + "name": "blsPubKey", + "type": "bytes" + } + ], + "internalType": "struct IStaking.CandidateV4[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + } +]` + +var _candidatesMethod abi.Method + +func init() { + _candidatesMethod = abiutil.MustLoadMethod(_candidatesInterfaceABI, "candidatesV4") +} + +func newCandidatesStateContext(data []byte) (*stakingComm.CandidatesStateContext, error) { + return stakingComm.NewCandidatesStateContext(data, &_candidatesMethod, iotexapi.ReadStakingDataMethod_CANDIDATES) +} diff --git a/action/protocol/staking/ethabi/v4/stakecandidatebyaddress_test.go b/action/protocol/staking/ethabi/v4/stakecandidatebyaddress_test.go new file mode 100644 index 0000000000..a8d8d6799b --- /dev/null +++ b/action/protocol/staking/ethabi/v4/stakecandidatebyaddress_test.go @@ -0,0 +1,71 @@ +package v4 + +import ( + "encoding/hex" + "reflect" + "testing" + + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + "github.com/iotexproject/iotex-core/v2/action/protocol" + stakingComm "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/common" +) + +func TestBuildReadStateRequestCandidateByAddress(t *testing.T) { + r := require.New(t) + + data, _ := hex.DecodeString("f7b5932c0000000000000000000000000000000000000000000000000000000000000001") + req, err := BuildReadStateRequest(data) + + r.Nil(err) + r.EqualValues("*common.CandidateByAddressStateContext", reflect.TypeOf(req).String()) + + method := &iotexapi.ReadStakingDataMethod{ + Method: iotexapi.ReadStakingDataMethod_CANDIDATE_BY_ADDRESS, + } + methodBytes, _ := proto.Marshal(method) + r.EqualValues(methodBytes, req.Parameters().MethodName) + + arguments := &iotexapi.ReadStakingDataRequest{ + Request: &iotexapi.ReadStakingDataRequest_CandidateByAddress_{ + CandidateByAddress: &iotexapi.ReadStakingDataRequest_CandidateByAddress{ + OwnerAddr: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + }, + }, + } + argumentsBytes, _ := proto.Marshal(arguments) + r.EqualValues([][]byte{argumentsBytes}, req.Parameters().Arguments) +} + +func TestCandidateByAddressToEth(t *testing.T) { + r := require.New(t) + + candidate := &iotextypes.CandidateV2{ + Id: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + OwnerAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + OperatorAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz75y8gn", + RewardAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrzsj4p", + Name: "hello", + TotalWeightedVotes: "10000000000000000000", + SelfStakeBucketIdx: 100, + SelfStakingTokens: "5000000000000000000", + BlsPubKey: []byte{0, 1, 2, 3}, + } + + candidateBytes, _ := proto.Marshal(candidate) + resp := &iotexapi.ReadStateResponse{ + Data: candidateBytes, + } + + ctx := &stakingComm.CandidateByAddressStateContext{ + BaseStateContext: &protocol.BaseStateContext{ + Method: &_candidateByAddressMethod, + }, + } + data, err := ctx.EncodeToEth(resp) + r.Nil(err) + r.EqualValues("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000568656c6c6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040001020300000000000000000000000000000000000000000000000000000000", data) +} diff --git a/action/protocol/staking/ethabi/v4/stakecandidatebyid_test.go b/action/protocol/staking/ethabi/v4/stakecandidatebyid_test.go new file mode 100644 index 0000000000..0faa0b0f44 --- /dev/null +++ b/action/protocol/staking/ethabi/v4/stakecandidatebyid_test.go @@ -0,0 +1,71 @@ +package v4 + +import ( + "encoding/hex" + "reflect" + "testing" + + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + "github.com/iotexproject/iotex-core/v2/action/protocol" + stakingComm "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/common" +) + +func TestBuildReadStateRequestCandidateByID(t *testing.T) { + r := require.New(t) + + data, _ := hex.DecodeString("91613c2e0000000000000000000000000000000000000000000000000000000000000001") + req, err := BuildReadStateRequest(data) + + r.Nil(err) + r.EqualValues("*common.CandidateByAddressStateContext", reflect.TypeOf(req).String()) + + method := &iotexapi.ReadStakingDataMethod{ + Method: iotexapi.ReadStakingDataMethod_CANDIDATE_BY_ADDRESS, + } + methodBytes, _ := proto.Marshal(method) + r.EqualValues(methodBytes, req.Parameters().MethodName) + + arguments := &iotexapi.ReadStakingDataRequest{ + Request: &iotexapi.ReadStakingDataRequest_CandidateByAddress_{ + CandidateByAddress: &iotexapi.ReadStakingDataRequest_CandidateByAddress{ + Id: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + }, + }, + } + argumentsBytes, _ := proto.Marshal(arguments) + r.EqualValues([][]byte{argumentsBytes}, req.Parameters().Arguments) +} + +func TestCandidateByIDToEth(t *testing.T) { + r := require.New(t) + + candidate := &iotextypes.CandidateV2{ + Id: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + OwnerAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + OperatorAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz75y8gn", + RewardAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrzsj4p", + Name: "hello", + TotalWeightedVotes: "10000000000000000000", + SelfStakeBucketIdx: 100, + SelfStakingTokens: "5000000000000000000", + BlsPubKey: []byte{0, 1, 2, 3}, + } + + candidateBytes, _ := proto.Marshal(candidate) + resp := &iotexapi.ReadStateResponse{ + Data: candidateBytes, + } + + ctx := &stakingComm.CandidateByAddressStateContext{ + BaseStateContext: &protocol.BaseStateContext{ + Method: &_candidateByIDMethod, + }, + } + data, err := ctx.EncodeToEth(resp) + r.Nil(err) + r.EqualValues("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000568656c6c6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040001020300000000000000000000000000000000000000000000000000000000", data) +} diff --git a/action/protocol/staking/ethabi/v4/stakecandidatebyname_test.go b/action/protocol/staking/ethabi/v4/stakecandidatebyname_test.go new file mode 100644 index 0000000000..1d758d0b5f --- /dev/null +++ b/action/protocol/staking/ethabi/v4/stakecandidatebyname_test.go @@ -0,0 +1,71 @@ +package v4 + +import ( + "encoding/hex" + "reflect" + "testing" + + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + "github.com/iotexproject/iotex-core/v2/action/protocol" + "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/common" +) + +func TestBuildReadStateRequestCandidateByName(t *testing.T) { + r := require.New(t) + + data, _ := hex.DecodeString("7fc242970000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000") + req, err := BuildReadStateRequest(data) + + r.Nil(err) + r.EqualValues("*common.CandidateByNameStateContext", reflect.TypeOf(req).String()) + + method := &iotexapi.ReadStakingDataMethod{ + Method: iotexapi.ReadStakingDataMethod_CANDIDATE_BY_NAME, + } + methodBytes, _ := proto.Marshal(method) + r.EqualValues(methodBytes, req.Parameters().MethodName) + + arguments := &iotexapi.ReadStakingDataRequest{ + Request: &iotexapi.ReadStakingDataRequest_CandidateByName_{ + CandidateByName: &iotexapi.ReadStakingDataRequest_CandidateByName{ + CandName: "hello", + }, + }, + } + argumentsBytes, _ := proto.Marshal(arguments) + r.EqualValues([][]byte{argumentsBytes}, req.Parameters().Arguments) +} + +func TestCandidateByNameToEth(t *testing.T) { + r := require.New(t) + + candidate := &iotextypes.CandidateV2{ + Id: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + OwnerAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + OperatorAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz75y8gn", + RewardAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrzsj4p", + Name: "hello", + TotalWeightedVotes: "10000000000000000000", + SelfStakeBucketIdx: 100, + SelfStakingTokens: "5000000000000000000", + BlsPubKey: []byte{0, 1, 2, 3}, + } + + candidateBytes, _ := proto.Marshal(candidate) + resp := &iotexapi.ReadStateResponse{ + Data: candidateBytes, + } + + ctx := &common.CandidateByNameStateContext{ + BaseStateContext: &protocol.BaseStateContext{ + Method: &_candidateByNameMethod, + }, + } + data, err := ctx.EncodeToEth(resp) + r.Nil(err) + r.EqualValues("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000568656c6c6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040001020300000000000000000000000000000000000000000000000000000000", data) +} diff --git a/action/protocol/staking/ethabi/v4/stakecandidates_test.go b/action/protocol/staking/ethabi/v4/stakecandidates_test.go new file mode 100644 index 0000000000..ed7fca730e --- /dev/null +++ b/action/protocol/staking/ethabi/v4/stakecandidates_test.go @@ -0,0 +1,108 @@ +package v4 + +import ( + "encoding/hex" + "reflect" + "testing" + + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + "github.com/iotexproject/iotex-core/v2/action/protocol" + "github.com/iotexproject/iotex-core/v2/action/protocol/staking/ethabi/common" +) + +func TestBuildReadStateRequestCandidates(t *testing.T) { + r := require.New(t) + + data, _ := hex.DecodeString("5198e15500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002") + req, err := BuildReadStateRequest(data) + + r.Nil(err) + r.EqualValues("*common.CandidatesStateContext", reflect.TypeOf(req).String()) + + method := &iotexapi.ReadStakingDataMethod{ + Method: iotexapi.ReadStakingDataMethod_CANDIDATES, + } + methodBytes, _ := proto.Marshal(method) + r.EqualValues(methodBytes, req.Parameters().MethodName) + + arguments := &iotexapi.ReadStakingDataRequest{ + Request: &iotexapi.ReadStakingDataRequest_Candidates_{ + Candidates: &iotexapi.ReadStakingDataRequest_Candidates{ + Pagination: &iotexapi.PaginationParam{ + Offset: 1, + Limit: 2, + }, + }, + }, + } + argumentsBytes, _ := proto.Marshal(arguments) + r.EqualValues([][]byte{argumentsBytes}, req.Parameters().Arguments) +} + +func TestCandidatesToEth(t *testing.T) { + r := require.New(t) + + candidates := &iotextypes.CandidateListV2{ + Candidates: []*iotextypes.CandidateV2{ + { + Id: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + OwnerAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqps833xv", + OperatorAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz75y8gn", + RewardAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrzsj4p", + Name: "hello", + TotalWeightedVotes: "10000000000000000000", + SelfStakeBucketIdx: 100, + SelfStakingTokens: "5000000000000000000", + BlsPubKey: []byte{0, 1, 2, 3}, + }, { + Id: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqyzm8z5y", + OwnerAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqyzm8z5y", + OperatorAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq9ldnhfk", + RewardAddress: "io1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqx37xp8f", + Name: "world", + TotalWeightedVotes: "11000000000000000000", + SelfStakeBucketIdx: 101, + SelfStakingTokens: "6000000000000000000", + BlsPubKey: []byte{4, 5, 6, 7}, + }, + }, + } + candidatesBytes, _ := proto.Marshal(candidates) + resp := &iotexapi.ReadStateResponse{ + Data: candidatesBytes, + } + + ctx := &common.CandidatesStateContext{ + BaseStateContext: &protocol.BaseStateContext{ + Method: &_candidatesMethod, + }, + } + data, err := ctx.EncodeToEth(resp) + r.Nil(err) + r.EqualValues("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000568656c6c6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040001020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000098a7d9b8314c0000000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000053444835ec580000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000005776f726c6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040405060700000000000000000000000000000000000000000000000000000000", data) +} + +func TestCandidatesToEthEmptyCandidates(t *testing.T) { + r := require.New(t) + + candidates := &iotextypes.CandidateListV2{ + Candidates: []*iotextypes.CandidateV2{}, + } + candidatesBytes, _ := proto.Marshal(candidates) + resp := &iotexapi.ReadStateResponse{ + Data: candidatesBytes, + } + + ctx := &common.CandidatesStateContext{ + BaseStateContext: &protocol.BaseStateContext{ + Method: &_candidatesMethod, + }, + } + data, err := ctx.EncodeToEth(resp) + r.Nil(err) + r.EqualValues("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", data) +} diff --git a/go.mod b/go.mod index aa23e34054..22d3975458 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/iotexproject/iotex-address v0.2.8 github.com/iotexproject/iotex-antenna-go/v2 v2.6.4 github.com/iotexproject/iotex-election v0.3.8-0.20250722071821-26e7794c6dcd - github.com/iotexproject/iotex-proto v0.6.5-0.20250805125222-9cdc028f4a74 + github.com/iotexproject/iotex-proto v0.6.5 github.com/ipfs/go-ipfs-api v0.7.0 github.com/libp2p/go-libp2p v0.39.0 github.com/mackerelio/go-osstat v0.2.4 diff --git a/go.sum b/go.sum index 18d258f211..b3c395e905 100644 --- a/go.sum +++ b/go.sum @@ -664,8 +664,8 @@ github.com/iotexproject/iotex-antenna-go/v2 v2.6.4 h1:7e0VyBDFT+iqwvr/BIk38yf7nC github.com/iotexproject/iotex-antenna-go/v2 v2.6.4/go.mod h1:L6AzDHo2TBFDAPA3ly+/PCS4JSX2g3zzhwV8RGQsTDI= github.com/iotexproject/iotex-election v0.3.8-0.20250722071821-26e7794c6dcd h1:HuIbAgT5Qi+hy0BsW8FuyZcxiTAwW3vQSI7nyMNWbMM= github.com/iotexproject/iotex-election v0.3.8-0.20250722071821-26e7794c6dcd/go.mod h1:w9HriT1coMRbuknaSD2xqiOqDTnowBDzvFZv8tg1j2M= -github.com/iotexproject/iotex-proto v0.6.5-0.20250805125222-9cdc028f4a74 h1:piMZ7PflGeuOKCv4xtgpM6w398tZd14EgF5BYuQ4TRs= -github.com/iotexproject/iotex-proto v0.6.5-0.20250805125222-9cdc028f4a74/go.mod h1:OOXZIG6Q9tInog8Y5zzEJQsDv9IaG/xxpDtl4KzdWZs= +github.com/iotexproject/iotex-proto v0.6.5 h1:EyzwDXYtGWvJ/qnYCwhqypOjpEAQPvESo+EdPcUJPE0= +github.com/iotexproject/iotex-proto v0.6.5/go.mod h1:OOXZIG6Q9tInog8Y5zzEJQsDv9IaG/xxpDtl4KzdWZs= github.com/ipfs/boxo v0.27.2 h1:sGo4KdwBaMjdBjH08lqPJyt27Z4CO6sugne3ryX513s= github.com/ipfs/boxo v0.27.2/go.mod h1:qEIRrGNr0bitDedTCzyzBHxzNWqYmyuHgK8LG9Q83EM= github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=