From c5faec916954c9de75bcee3ba4d81eb3e2db79b0 Mon Sep 17 00:00:00 2001 From: dustinxie Date: Fri, 1 Jul 2022 16:27:21 -0700 Subject: [PATCH] add SetChainID() to caller interface (#102) --- README.md | 21 ++++++++++---- iotex/caller_claimreward.go | 5 ++++ iotex/caller_contract.go | 10 +++++++ iotex/caller_staking.go | 5 ++++ iotex/caller_transfer.go | 5 ++++ iotex/callers.go | 10 +++++++ iotex/interfaces.go | 4 +++ iotex/interfaces_mock.go | 56 +++++++++++++++++++++++++++++++++++++ iotex/iotex_test.go | 30 ++++++++++++++------ 9 files changed, 132 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 72cb3974..778bec78 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,11 @@ go get github.com/iotexproject/iotex-antenna-go/v2 ``` ### Code It Up +The below example code shows the 4 easy steps to send a transaction to IoTeX blockchain +1. connect to the chain's RPC endpoint +2. create an account by importing a private key +3. create a client and generate an action sender +4. send the transaction to the chain ``` package main @@ -38,12 +43,15 @@ import ( ) const ( - host = "api.testnet.iotex.one:443" + mainnetRPC = "api.iotex.one:443" + testnetRPC = "api.testnet.iotex.one:443" + mainnetChainID = 1 + testnetChainID = 2 ) func main() { // Create grpc connection - conn, err := iotex.NewDefaultGRPCConn(host) + conn, err := iotex.NewDefaultGRPCConn(testnetRPC) if err != nil { log.Fatal(err) } @@ -57,16 +65,17 @@ func main() { // create client c := iotex.NewAuthedClient(iotexapi.NewAPIServiceClient(conn), acc) - - // transfer - to, err := address.FromString("to...") + + // send the transfer to chain + to, err := address.FromString("io1zq5g9c5c3hqw9559ks4anptkpumxgsjfn2e4ke") if err != nil { log.Fatal(err) } - hash, err := c.Transfer(to, big.NewInt(10)).Call(context.Background()) + hash, err := c.Transfer(to, big.NewInt(10)).SetChainID(testnetChainID).SetGasPrice(big.NewInt(100000000000)).SetGasLimit(20000).Call(context.Background()) if err != nil { log.Fatal(err) } + fmt.Println("transaction hash = %x\n", hash) } ``` diff --git a/iotex/caller_claimreward.go b/iotex/caller_claimreward.go index 9f4300b2..822703c8 100644 --- a/iotex/caller_claimreward.go +++ b/iotex/caller_claimreward.go @@ -37,6 +37,11 @@ func (c *claimRewardCaller) SetGasPrice(g *big.Int) ClaimRewardCaller { return c } +func (c *claimRewardCaller) SetChainID(id uint32) ClaimRewardCaller { + c.sendActionCaller.setChainID(id) + return c +} + func (c *claimRewardCaller) SetNonce(n uint64) ClaimRewardCaller { c.sendActionCaller.setNonce(n) return c diff --git a/iotex/caller_contract.go b/iotex/caller_contract.go index 6e9a1905..1876ff0d 100644 --- a/iotex/caller_contract.go +++ b/iotex/caller_contract.go @@ -45,6 +45,11 @@ func (c *deployContractCaller) SetGasPrice(g *big.Int) DeployContractCaller { return c } +func (c *deployContractCaller) SetChainID(id uint32) DeployContractCaller { + c.sendActionCaller.setChainID(id) + return c +} + func (c *deployContractCaller) SetNonce(n uint64) DeployContractCaller { c.sendActionCaller.setNonce(n) return c @@ -106,6 +111,11 @@ func (c *executeContractCaller) SetGasPrice(g *big.Int) ExecuteContractCaller { return c } +func (c *executeContractCaller) SetChainID(id uint32) ExecuteContractCaller { + c.sendActionCaller.setChainID(id) + return c +} + func (c *executeContractCaller) SetNonce(n uint64) ExecuteContractCaller { c.sendActionCaller.setNonce(n) return c diff --git a/iotex/caller_staking.go b/iotex/caller_staking.go index c8d6786a..2567be40 100644 --- a/iotex/caller_staking.go +++ b/iotex/caller_staking.go @@ -148,6 +148,11 @@ func (c *stakingCaller) SetNonce(n uint64) SendActionCaller { return c } +func (c *stakingCaller) SetChainID(id uint32) SendActionCaller { + c.sendActionCaller.setChainID(id) + return c +} + func (c *stakingCaller) SetPayload(pl []byte) SendActionCaller { c.sendActionCaller.setPayload(pl) return c diff --git a/iotex/caller_transfer.go b/iotex/caller_transfer.go index ce6ac03c..f645294f 100644 --- a/iotex/caller_transfer.go +++ b/iotex/caller_transfer.go @@ -39,6 +39,11 @@ func (c *transferCaller) SetGasPrice(g *big.Int) SendActionCaller { return c } +func (c *transferCaller) SetChainID(id uint32) SendActionCaller { + c.sendActionCaller.setChainID(id) + return c +} + func (c *transferCaller) SetNonce(n uint64) SendActionCaller { c.sendActionCaller.setNonce(n) return c diff --git a/iotex/callers.go b/iotex/callers.go index dfdef240..00a23698 100644 --- a/iotex/callers.go +++ b/iotex/callers.go @@ -31,6 +31,7 @@ type sendActionCaller struct { nonce uint64 gasLimit uint64 gasPrice *big.Int + chainID uint32 payload []byte core *iotextypes.ActionCore } @@ -44,6 +45,10 @@ func (c *sendActionCaller) setNonce(n uint64) { c.nonce = n } +func (c *sendActionCaller) setChainID(id uint32) { + c.chainID = id +} + func (c *sendActionCaller) setGasLimit(g uint64) { c.gasLimit = g } @@ -61,6 +66,11 @@ func (c *sendActionCaller) setPayload(pl []byte) { } func (c *sendActionCaller) Call(ctx context.Context, opts ...grpc.CallOption) (hash.Hash256, error) { + if c.chainID == 0 { + return hash.ZeroHash256, errcodes.New("0 is not a valid chain ID (use 1 for mainnet, 2 for testnet)", errcodes.InvalidParam) + } + c.core.ChainID = c.chainID + if c.nonce == 0 { res, err := c.api.GetAccount(ctx, &iotexapi.GetAccountRequest{Address: c.account.Address().String()}, opts...) if err != nil { diff --git a/iotex/interfaces.go b/iotex/interfaces.go index d84f0c4e..08c18556 100644 --- a/iotex/interfaces.go +++ b/iotex/interfaces.go @@ -24,6 +24,7 @@ type SendActionCaller interface { SetNonce(uint64) SendActionCaller SetGasLimit(uint64) SendActionCaller SetGasPrice(*big.Int) SendActionCaller + SetChainID(uint32) SendActionCaller SetPayload([]byte) SendActionCaller } @@ -33,6 +34,7 @@ type ClaimRewardCaller interface { SetGasPrice(*big.Int) ClaimRewardCaller SetGasLimit(uint64) ClaimRewardCaller + SetChainID(uint32) ClaimRewardCaller SetData([]byte) ClaimRewardCaller SetNonce(uint64) ClaimRewardCaller } @@ -80,6 +82,7 @@ type ExecuteContractCaller interface { SetGasPrice(*big.Int) ExecuteContractCaller SetGasLimit(uint64) ExecuteContractCaller + SetChainID(uint32) ExecuteContractCaller SetAmount(*big.Int) ExecuteContractCaller SetNonce(uint64) ExecuteContractCaller } @@ -91,6 +94,7 @@ type DeployContractCaller interface { SetArgs(abi abi.ABI, args ...interface{}) DeployContractCaller SetGasPrice(*big.Int) DeployContractCaller SetGasLimit(uint64) DeployContractCaller + SetChainID(uint32) DeployContractCaller SetNonce(uint64) DeployContractCaller } diff --git a/iotex/interfaces_mock.go b/iotex/interfaces_mock.go index b063311f..cf911925 100644 --- a/iotex/interfaces_mock.go +++ b/iotex/interfaces_mock.go @@ -132,6 +132,20 @@ func (mr *MockSendActionCallerMockRecorder) Call(ctx interface{}, opts ...interf return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockSendActionCaller)(nil).Call), varargs...) } +// SetChainID mocks base method. +func (m *MockSendActionCaller) SetChainID(arg0 uint32) SendActionCaller { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetChainID", arg0) + ret0, _ := ret[0].(SendActionCaller) + return ret0 +} + +// SetChainID indicates an expected call of SetChainID. +func (mr *MockSendActionCallerMockRecorder) SetChainID(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetChainID", reflect.TypeOf((*MockSendActionCaller)(nil).SetChainID), arg0) +} + // SetGasLimit mocks base method. func (m *MockSendActionCaller) SetGasLimit(arg0 uint64) SendActionCaller { m.ctrl.T.Helper() @@ -245,6 +259,20 @@ func (mr *MockClaimRewardCallerMockRecorder) Call(ctx interface{}, opts ...inter return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockClaimRewardCaller)(nil).Call), varargs...) } +// SetChainID mocks base method. +func (m *MockClaimRewardCaller) SetChainID(arg0 uint32) ClaimRewardCaller { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetChainID", arg0) + ret0, _ := ret[0].(ClaimRewardCaller) + return ret0 +} + +// SetChainID indicates an expected call of SetChainID. +func (mr *MockClaimRewardCallerMockRecorder) SetChainID(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetChainID", reflect.TypeOf((*MockClaimRewardCaller)(nil).SetChainID), arg0) +} + // SetData mocks base method. func (m *MockClaimRewardCaller) SetData(arg0 []byte) ClaimRewardCaller { m.ctrl.T.Helper() @@ -757,6 +785,20 @@ func (mr *MockExecuteContractCallerMockRecorder) SetAmount(arg0 interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAmount", reflect.TypeOf((*MockExecuteContractCaller)(nil).SetAmount), arg0) } +// SetChainID mocks base method. +func (m *MockExecuteContractCaller) SetChainID(arg0 uint32) ExecuteContractCaller { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetChainID", arg0) + ret0, _ := ret[0].(ExecuteContractCaller) + return ret0 +} + +// SetChainID indicates an expected call of SetChainID. +func (mr *MockExecuteContractCallerMockRecorder) SetChainID(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetChainID", reflect.TypeOf((*MockExecuteContractCaller)(nil).SetChainID), arg0) +} + // SetGasLimit mocks base method. func (m *MockExecuteContractCaller) SetGasLimit(arg0 uint64) ExecuteContractCaller { m.ctrl.T.Helper() @@ -875,6 +917,20 @@ func (mr *MockDeployContractCallerMockRecorder) SetArgs(abi interface{}, args .. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetArgs", reflect.TypeOf((*MockDeployContractCaller)(nil).SetArgs), varargs...) } +// SetChainID mocks base method. +func (m *MockDeployContractCaller) SetChainID(arg0 uint32) DeployContractCaller { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetChainID", arg0) + ret0, _ := ret[0].(DeployContractCaller) + return ret0 +} + +// SetChainID indicates an expected call of SetChainID. +func (mr *MockDeployContractCallerMockRecorder) SetChainID(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetChainID", reflect.TypeOf((*MockDeployContractCaller)(nil).SetChainID), arg0) +} + // SetGasLimit mocks base method. func (m *MockDeployContractCaller) SetGasLimit(arg0 uint64) DeployContractCaller { m.ctrl.T.Helper() diff --git a/iotex/iotex_test.go b/iotex/iotex_test.go index e38b7454..5a14a024 100644 --- a/iotex/iotex_test.go +++ b/iotex/iotex_test.go @@ -47,9 +47,23 @@ func TestTransfer(t *testing.T) { to, err := address.FromString(_to) require.NoError(err) v := big.NewInt(160000000000000000) - hash, err := c.Transfer(to, v).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).Call(context.Background()) - require.NoError(err) - require.NotEmpty(hash) + caller := c.Transfer(to, v) + for _, test := range []struct { + chainID uint32 + err string + }{ + {0, "0 is not a valid chain ID (use 1 for mainnet, 2 for testnet)"}, + {1, "ChainID does not match, expecting 2, got 1"}, + {2, ""}, + } { + hash, err := caller.SetChainID(test.chainID).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).Call(context.Background()) + if len(test.err) > 0 { + require.Contains(err.Error(), test.err) + } else { + require.NoError(err) + require.NotEmpty(hash) + } + } } func TestStake(t *testing.T) { @@ -64,7 +78,7 @@ func TestStake(t *testing.T) { one := big.NewInt(int64(unit.Iotx)) hash, err := c.Staking().Create("robotbp00001", one.Lsh(one, 7), 0, false). - SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(20000).Call(context.Background()) + SetChainID(2).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(20000).Call(context.Background()) require.Contains(err.Error(), "insufficient funds for gas * price + value") require.NotEmpty(hash) } @@ -81,7 +95,7 @@ func TestClaimReward(t *testing.T) { require.NoError(err) v := big.NewInt(1000000000000000000) - hash, err := c.ClaimReward(v).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).Call(context.Background()) + hash, err := c.ClaimReward(v).SetChainID(2).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).Call(context.Background()) require.NoError(err) require.NotEmpty(hash) } @@ -101,7 +115,7 @@ func TestDeployContract(t *testing.T) { data, err := hex.DecodeString("608060405234801561001057600080fd5b506040516020806100f2833981016040525160005560bf806100336000396000f30060806040526004361060485763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166360fe47b18114604d5780636d4ce63c146064575b600080fd5b348015605857600080fd5b5060626004356088565b005b348015606f57600080fd5b506076608d565b60408051918252519081900360200190f35b600055565b600054905600a165627a7a723058208d4f6c9737f34d9b28ef070baa8127c0876757fbf6f3945a7ea8d4387ca156590029") require.NoError(err) - hash, err := c.DeployContract(data).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).SetArgs(abi, big.NewInt(10)).Call(context.Background()) + hash, err := c.DeployContract(data).SetGasPrice(big.NewInt(int64(unit.Qev))).SetChainID(2).SetGasLimit(1000000).SetArgs(abi, big.NewInt(10)).Call(context.Background()) require.NoError(err) require.NotNil(hash) } @@ -120,7 +134,7 @@ func TestExecuteContract(t *testing.T) { contract, err := address.FromString("io17sn486alutrnzlrdz9vv44g7qyc38hygf7s6h0") require.NoError(err) - hash, err := c.Contract(contract, abi).Execute("set", big.NewInt(8)).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).Call(context.Background()) + hash, err := c.Contract(contract, abi).Execute("set", big.NewInt(8)).SetChainID(2).SetGasPrice(big.NewInt(int64(unit.Qev))).SetGasLimit(1000000).Call(context.Background()) require.NoError(err) require.NotNil(hash) } @@ -211,7 +225,7 @@ func TestExecuteContractWithAddressArgument(t *testing.T) { recipients := [2]address.Address{recipient1, recipient2} // recipients := [2]string{"io18jaldgzc8wlyfnzamgas62yu3kg5nw527czg37", "io1ntprz4p5zw38fvtfrcczjtcv3rkr3nqs6sm3pj"} amounts := [2]*big.Int{big.NewInt(1), big.NewInt(2)} - actionHash, err := c.Contract(contract, abi).Execute("multiSend", recipients, amounts, "payload").SetGasPrice(big.NewInt(1000000000000)).SetGasLimit(1000000).Call(context.Background()) + actionHash, err := c.Contract(contract, abi).Execute("multiSend", recipients, amounts, "payload").SetChainID(2).SetGasPrice(big.NewInt(1000000000000)).SetGasLimit(1000000).Call(context.Background()) require.NoError(err) require.NotNil(actionHash) }