From 8cc717d932007c0a99e2ca13e32ca489a671193d Mon Sep 17 00:00:00 2001 From: Dayong Wang Date: Tue, 12 May 2020 14:57:55 +0800 Subject: [PATCH 1/5] list mapping table of solidity types to go types --- README.md | 20 +++++++++++++++++++- client.go | 2 +- contract.go | 12 ++++++++++++ types/wrapped_error.go | 3 +-- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ca3b7a2..1527f0a 100644 --- a/README.md +++ b/README.md @@ -214,4 +214,22 @@ func main() { fmt.Printf("decoded transfer event: {From: 0x%x, To: 0x%x, Value: %v} ", Transfer.From, Transfer.To, Transfer.Value) } -``` \ No newline at end of file +``` +## Appendix +### Mapping of solidity types to go types +This is a mapping table for map solidity types to go types when using contract methods GetData/Call/SendTransaction/DecodeEvent +| solidity types | go types | +|----------------------------------------------|-----------------------------------------------------------------------------------| +| address | common.Address | +| uint8,uint16,uint32,uint64 | uint8,uint16,uint32,uint64 | +| uint24,uint40,uint48,uint56,uint72...uint256 | *big.Int | +| int8,int16,int32,int64 | int8,int16,int32,int64 | +| int24,int40,int48,int56,int72...int256 | *big.Int | +| fixed bytes (bytes1,bytes2...bytes32) | [length]byte | +| fixed type T array (T[length]) | [length]TG (TG is go type matched with solidty type T) | +| bytes | []byte | +| dynamic type T array T[] | []TG ((TG is go type matched with solidty type T)) | +| function | [24]byte | +| string | string | +| bool | bool | +| tuple | struct eg:[{"name": "balance","type": "uint256"}] => struct {Balance *big.Int} | diff --git a/client.go b/client.go index 1842d0a..b277f3d 100644 --- a/client.go +++ b/client.go @@ -694,7 +694,7 @@ func (client *Client) DeployContract(option *types.ContractDeployOption, abiJSON msg := fmt.Sprintf("deploy contract time out after %v, txhash is %+v", t, txhash) result.Error = errors.New(msg) return - // Got a tick, we should check on checkSomething() + // Got a tick case <-ticker: transaction, err := client.GetTransactionByHash(txhash) if err != nil { diff --git a/contract.go b/contract.go index 18d9793..248755f 100644 --- a/contract.go +++ b/contract.go @@ -37,6 +37,9 @@ type ContractDeployResult struct { // of 4 bytes and arguments are all 32 bytes. // Method ids are created from the first 4 bytes of the hash of the // methods string signature. (signature = baz(uint32,string32)) +// +// please refer https://github.com/Conflux-Chain/go-conflux-sdk/blob/master/README.md to +// get the mappings of solidity types to go types func (contract *Contract) GetData(method string, args ...interface{}) ([]byte, error) { packed, err := contract.ABI.Pack(method, args...) if err != nil { @@ -50,6 +53,9 @@ func (contract *Contract) GetData(method string, args ...interface{}) ([]byte, e // Call calls to the contract method with args and fills the excuted result to the "resultPtr". // // the resultPtr should be a pointer of the method output struct type. +// +// please refer https://github.com/Conflux-Chain/go-conflux-sdk/blob/master/README.md to +// get the mappings of solidity types to go types func (contract *Contract) Call(option *types.ContractMethodCallOption, resultPtr interface{}, method string, args ...interface{}) error { data, err := contract.GetData(method, args...) @@ -93,6 +99,9 @@ func (contract *Contract) Call(option *types.ContractMethodCallOption, resultPtr } // SendTransaction sends a transaction to the contract method with args and returns its transaction hash +// +// please refer https://github.com/Conflux-Chain/go-conflux-sdk/blob/master/README.md to +// get the mappings of solidity types to go types func (contract *Contract) SendTransaction(option *types.ContractMethodSendOption, method string, args ...interface{}) (*types.Hash, error) { data, err := contract.GetData(method, args...) @@ -123,6 +132,9 @@ func (contract *Contract) SendTransaction(option *types.ContractMethodSendOption } // DecodeEvent unpacks a retrieved log into the provided output structure. +// +// please refer https://github.com/Conflux-Chain/go-conflux-sdk/blob/master/README.md to +// get the mappings of solidity types to go types func (contract *Contract) DecodeEvent(out interface{}, event string, log types.LogEntry) error { topics := make([]common.Hash, len(log.Topics)) diff --git a/types/wrapped_error.go b/types/wrapped_error.go index aae22f7..7314ebc 100644 --- a/types/wrapped_error.go +++ b/types/wrapped_error.go @@ -3,7 +3,6 @@ package types import ( "fmt" "reflect" - "strings" ) // WrappedError for wrapping old error and new error message @@ -28,7 +27,7 @@ func (e WrappedError) Error() string { var innerErrorMsg string if e.err != nil { t := reflect.TypeOf(e.err).String() - isJSONErr := strings.Contains(t, "rpc.jsonError") + isJSONErr := t == "*rpc.jsonError" if isJSONErr { elem := reflect.ValueOf(e.err).Elem() data := elem.FieldByName("Data") From 6e4d268c5ce911e7b4f94d3745d3a33ddbae859f Mon Sep 17 00:00:00 2001 From: Dayong Wang Date: Tue, 12 May 2020 16:47:55 +0800 Subject: [PATCH 2/5] support client with retry --- client.go | 118 +++++++++++++++++++++++++++++++++++++++------------ interface.go | 5 +++ 2 files changed, 97 insertions(+), 26 deletions(-) diff --git a/client.go b/client.go index b277f3d..10ec4bd 100644 --- a/client.go +++ b/client.go @@ -20,20 +20,86 @@ import ( // Client represents a client to interact with Conflux blockchain. type Client struct { - rpcClient *rpc.Client + rpcRequester rpcRequester accountManager AccountManagerOperator } // NewClient creates a new instance of Client with specified conflux node url. func NewClient(nodeURL string) (*Client, error) { - client, err := rpc.Dial(nodeURL) + client, err := NewClientWithRetry(nodeURL, 0, 0) + return client, err +} + +// NewClientWithRetry creates a retryable new instance of Client with specified conflux node url and retry options. +// +// the retryInterval will be set to 1 second if pass 0 +func NewClientWithRetry(nodeURL string, retryCount int, retryInterval time.Duration) (*Client, error) { + + var client Client + + rpcClient, err := rpc.Dial(nodeURL) if err != nil { return nil, types.WrapError(err, "dail failed") } - return &Client{ - rpcClient: client, - }, nil + if retryCount == 0 { + client.rpcRequester = rpcClient + } else { + // Interval 0 is meaningless and may lead full node busy, so default sets it to 1 second + if retryInterval == 0 { + retryInterval = time.Second + } + + client.rpcRequester = &rpcClientWithRetry{ + inner: rpcClient, + retryCount: retryCount, + interval: retryInterval, + } + } + + return &client, nil +} + +type rpcClientWithRetry struct { + inner *rpc.Client + retryCount int + interval time.Duration +} + +func (r *rpcClientWithRetry) Call(resultPtr interface{}, method string, args ...interface{}) error { + err := r.inner.Call(resultPtr, method, args...) + if err == nil { + return nil + } + + if r.retryCount <= 0 { + return err + } + + remain := r.retryCount + remain-- + for { + err = r.inner.Call(resultPtr, method, args...) + if err == nil { + return nil + } + + remain-- + if remain == 0 { + msg := fmt.Sprintf("timeout when call %v with args %v", method, args) + return types.WrapError(err, msg) + } + + if r.interval > 0 { + time.Sleep(r.interval) + } + } +} + +func (r *rpcClientWithRetry) Close() { + if r != nil && r.inner != nil { + r.inner.Close() + } } // CallRPC performs a JSON-RPC call with the given arguments and unmarshals into @@ -42,7 +108,7 @@ func NewClient(nodeURL string) (*Client, error) { // The result must be a pointer so that package json can unmarshal into it. You // can also pass nil, in which case the result is ignored. func (client *Client) CallRPC(result interface{}, method string, args ...interface{}) error { - return client.rpcClient.Call(result, method, args...) + return client.rpcRequester.Call(result, method, args...) } // SetAccountManager sets account manager for sign transaction @@ -54,7 +120,7 @@ func (client *Client) SetAccountManager(accountManager AccountManagerOperator) { func (client *Client) GetGasPrice() (*big.Int, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_gasPrice"); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_gasPrice"); err != nil { msg := "rpc request cfx_gasPrice error" return nil, types.WrapError(err, msg) } @@ -70,7 +136,7 @@ func (client *Client) GetNextNonce(address types.Address, epoch *types.Epoch) (* args = append(args, epoch) } - if err := client.rpcClient.Call(&result, "cfx_getNextNonce", args...); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getNextNonce", args...); err != nil { msg := fmt.Sprintf("rpc request cfx_getNextNonce %+v error", address) return nil, types.WrapErrorf(err, msg) } @@ -96,7 +162,7 @@ func (client *Client) GetEpochNumber(epoch ...*types.Epoch) (*big.Int, error) { args = append(args, epoch[0]) } - if err := client.rpcClient.Call(&result, "cfx_epochNumber", args...); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_epochNumber", args...); err != nil { msg := fmt.Sprintf("rpc cfx_epochNumber %+v error", args) return nil, types.WrapError(err, msg) } @@ -113,7 +179,7 @@ func (client *Client) GetBalance(address types.Address, epoch ...*types.Epoch) ( args = append(args, epoch[0]) } - if err := client.rpcClient.Call(&result, "cfx_getBalance", args...); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getBalance", args...); err != nil { msg := fmt.Sprintf("rpc cfx_getBalance %+v error", args) return nil, types.WrapError(err, msg) } @@ -130,7 +196,7 @@ func (client *Client) GetCode(address types.Address, epoch ...*types.Epoch) (str args = append(args, epoch[0]) } - if err := client.rpcClient.Call(&result, "cfx_getCode", args...); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getCode", args...); err != nil { msg := fmt.Sprintf("rpc cfx_getCode %+v error", args) return "", types.WrapError(err, msg) } @@ -143,7 +209,7 @@ func (client *Client) GetCode(address types.Address, epoch ...*types.Epoch) (str func (client *Client) GetBlockSummaryByHash(blockHash types.Hash) (*types.BlockSummary, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_getBlockByHash", blockHash, false); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getBlockByHash", blockHash, false); err != nil { msg := fmt.Sprintf("rpc cfx_getBlockByHash %+v error", blockHash) return nil, types.WrapError(err, msg) } @@ -166,7 +232,7 @@ func (client *Client) GetBlockSummaryByHash(blockHash types.Hash) (*types.BlockS func (client *Client) GetBlockByHash(blockHash types.Hash) (*types.Block, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_getBlockByHash", blockHash, true); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getBlockByHash", blockHash, true); err != nil { msg := fmt.Sprintf("rpc cfx_getBlockByHash %+v error", blockHash) return nil, types.WrapError(err, msg) } @@ -189,7 +255,7 @@ func (client *Client) GetBlockByHash(blockHash types.Hash) (*types.Block, error) func (client *Client) GetBlockSummaryByEpoch(epoch *types.Epoch) (*types.BlockSummary, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_getBlockByEpochNumber", epoch, false); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getBlockByEpochNumber", epoch, false); err != nil { msg := fmt.Sprintf("rpc cfx_getBlockByEpochNumber %+v error", epoch) return nil, types.WrapError(err, msg) } @@ -208,7 +274,7 @@ func (client *Client) GetBlockSummaryByEpoch(epoch *types.Epoch) (*types.BlockSu func (client *Client) GetBlockByEpoch(epoch *types.Epoch) (*types.Block, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_getBlockByEpochNumber", epoch, true); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getBlockByEpochNumber", epoch, true); err != nil { msg := fmt.Sprintf("rpc cfx_getBlockByEpochNumber %+v error", epoch) return nil, types.WrapError(err, msg) } @@ -226,7 +292,7 @@ func (client *Client) GetBlockByEpoch(epoch *types.Epoch) (*types.Block, error) func (client *Client) GetBestBlockHash() (types.Hash, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_getBestBlockHash"); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getBestBlockHash"); err != nil { msg := "rpc cfx_getBestBlockHash error" return "", types.WrapError(err, msg) } @@ -241,7 +307,7 @@ func (client *Client) GetBlockConfirmRiskByHash(blockhash types.Hash) (*big.Int, args := []interface{}{blockhash} - if err := client.rpcClient.Call(&result, "cfx_getConfirmationRiskByHash", args...); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getConfirmationRiskByHash", args...); err != nil { msg := fmt.Sprintf("rpc cfx_getConfirmationRiskByHash %+v error", args) return nil, types.WrapError(err, msg) } @@ -343,7 +409,7 @@ func (client *Client) SendTransaction(tx *types.UnsignedTransaction) (types.Hash func (client *Client) SendRawTransaction(rawData []byte) (types.Hash, error) { var result interface{} // fmt.Printf("send raw transaction %x\n", rawData) - if err := client.rpcClient.Call(&result, "cfx_sendRawTransaction", hexutil.Encode(rawData)); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_sendRawTransaction", hexutil.Encode(rawData)); err != nil { msg := fmt.Sprintf("rpc cfx_sendRawTransaction 0x%+x error", rawData) return "", types.WrapError(err, msg) } @@ -405,7 +471,7 @@ func (client *Client) Call(request types.CallRequest, epoch *types.Epoch) (*stri args = append(args, epoch) } - if err := client.rpcClient.Call(&rpcResult, "cfx_call", args...); err != nil { + if err := client.rpcRequester.Call(&rpcResult, "cfx_call", args...); err != nil { msg := fmt.Sprintf("rpc cfx_call {%+v} error", args) return nil, types.WrapError(err, msg) } @@ -422,7 +488,7 @@ func (client *Client) Call(request types.CallRequest, epoch *types.Epoch) (*stri func (client *Client) GetLogs(filter types.LogFilter) ([]types.Log, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_getLogs", filter); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getLogs", filter); err != nil { msg := fmt.Sprintf("rpc cfx_getLogs of {%+v} error", filter) return nil, types.WrapError(err, msg) } @@ -441,7 +507,7 @@ func (client *Client) GetLogs(filter types.LogFilter) ([]types.Log, error) { func (client *Client) GetTransactionByHash(txHash types.Hash) (*types.Transaction, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_getTransactionByHash", txHash); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getTransactionByHash", txHash); err != nil { msg := fmt.Sprintf("rpc cfx_getTransactionByHash {%+v} error", txHash) return nil, types.WrapError(err, msg) } @@ -466,7 +532,7 @@ func (client *Client) EstimateGasAndCollateral(request types.CallRequest) (*type args := []interface{}{request} - if err := client.rpcClient.Call(&result, "cfx_estimateGasAndCollateral", args...); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_estimateGasAndCollateral", args...); err != nil { msg := fmt.Sprintf("rpc cfx_estimateGasAndCollateral of {%+v} error", args) return nil, types.WrapError(err, msg) } @@ -483,7 +549,7 @@ func (client *Client) EstimateGasAndCollateral(request types.CallRequest) (*type func (client *Client) GetBlocksByEpoch(epoch *types.Epoch) ([]types.Hash, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_getBlocksByEpoch", epoch); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getBlocksByEpoch", epoch); err != nil { msg := fmt.Sprintf("rpc cfx_getBlocksByEpoch {%+v} error", epoch) return nil, types.WrapError(err, msg) } @@ -502,7 +568,7 @@ func (client *Client) GetBlocksByEpoch(epoch *types.Epoch) ([]types.Hash, error) func (client *Client) GetTransactionReceipt(txHash types.Hash) (*types.TransactionReceipt, error) { var result interface{} - if err := client.rpcClient.Call(&result, "cfx_getTransactionReceipt", txHash); err != nil { + if err := client.rpcRequester.Call(&result, "cfx_getTransactionReceipt", txHash); err != nil { msg := fmt.Sprintf("rpc cfx_getTransactionReceipt of {%+v} error", txHash) return nil, types.WrapError(err, msg) } @@ -620,7 +686,7 @@ func (client *Client) ApplyUnsignedTransactionDefault(tx *types.UnsignedTransact func (client *Client) Debug(method string, args ...interface{}) (interface{}, error) { var result interface{} - if err := client.rpcClient.Call(&result, method, args...); err != nil { + if err := client.rpcRequester.Call(&result, method, args...); err != nil { msg := fmt.Sprintf("rpc call method {%+v} with args {%+v} error", method, args) return nil, types.WrapError(err, msg) } @@ -734,7 +800,7 @@ func (client *Client) GetContract(abiJSON []byte, deployedAt *types.Address) (*C // Close closes the client, aborting any in-flight requests. func (client *Client) Close() { - client.rpcClient.Close() + client.rpcRequester.Close() } func unmarshalRPCResult(result interface{}, v interface{}) error { diff --git a/interface.go b/interface.go index c690371..00fb9e4 100644 --- a/interface.go +++ b/interface.go @@ -77,3 +77,8 @@ type AccountManagerOperator interface { SignTransactionWithPassphrase(tx types.UnsignedTransaction, passphrase string) (*types.SignedTransaction, error) Sign(tx types.UnsignedTransaction, passphrase string) (v byte, r, s []byte, err error) } + +type rpcRequester interface { + Call(resultPtr interface{}, method string, args ...interface{}) error + Close() +} From e57495f175e1ff33fd1130d1350cd4ec6361ff61 Mon Sep 17 00:00:00 2001 From: Dayong Wang Date: Tue, 12 May 2020 18:25:12 +0800 Subject: [PATCH 3/5] add example for client --- example/example_client/main.go | 213 +++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 example/example_client/main.go diff --git a/example/example_client/main.go b/example/example_client/main.go new file mode 100644 index 0000000..6911f1d --- /dev/null +++ b/example/example_client/main.go @@ -0,0 +1,213 @@ +package main + +import ( + "fmt" + "math/big" + "time" + + sdk "github.com/Conflux-Chain/go-conflux-sdk" + "github.com/Conflux-Chain/go-conflux-sdk/types" +) + +var am *sdk.AccountManager + +func main() { + //unlock account + am = sdk.NewAccountManager("../keystore") + err := am.TimedUnlockDefault("hello", 300*time.Second) + if err != nil { + panic(err) + } + + //init client without retry and excute it + client, err := sdk.NewClient("http://testnet-jsonrpc.conflux-chain.org:12537") + if err != nil { + panic(err) + } + client.SetAccountManager(am) + fmt.Println("start excute client methods without retry") + run(client) + + //init client with retry and excute it + client, err = sdk.NewClientWithRetry("http://testnet-jsonrpc.conflux-chain.org:12537", 10, 1) + if err != nil { + panic(err) + } + client.SetAccountManager(am) + fmt.Println("\n======================================") + fmt.Println("start excute client methods with retry") + run(client) +} + +func run(client *sdk.Client) { + gasPrice, err := client.GetGasPrice() + if err != nil { + fmt.Printf("gasprice error: %#v\n\n", err) + } + fmt.Printf("gasprice: %#v\n\n", gasPrice) + + epochs := []*types.Epoch{nil, types.EpochLatestState, types.NewEpochNumber(big.NewInt(1061848))} + for _, e := range epochs { + nonce, err := client.GetNextNonce(types.Address("0x19f4bcf113e0b896d9b34294fd3da86b4adf0302"), e) + if err != nil { + fmt.Printf("nonce of epoch %v error: %v\n\n", e, err) + } + fmt.Printf("nonce of epoch %v : %v\n\n", e, nonce) + } + + addr := types.Address("0x19f4bcf113e0b896d9b34294fd3da86b4adf0302") + balance, err := client.GetBalance(addr) + if err != nil { + fmt.Printf("get balance of %v: %v\n\n", addr, err) + } + fmt.Printf("balance of %v: %#v\n\n", addr, balance) + + bestBlockHash, err := client.GetBestBlockHash() + if err != nil { + fmt.Printf("get best block hash error: %v\n\n", err) + } + fmt.Printf("best block hash: %#v\n\n", bestBlockHash) + + epochNumber, err := client.GetEpochNumber() + if err != nil { + fmt.Printf("get epochNumber error: %#v\n\n", err) + } + fmt.Printf("epochNumber: %#v\n\n", epochNumber) + + epochNumber = big.NewInt(10) + block, err := client.GetBlockByEpoch(types.NewEpochNumber(epochNumber)) + if err != nil { + fmt.Printf("get block of epoch %v error:%#v\n\n", epochNumber, err) + } + fmt.Printf("block of epoch %v:%#v\n\n", epochNumber, block) + + blocks, err := client.GetBlocksByEpoch(types.NewEpochNumber(epochNumber)) + if err != nil { + fmt.Printf("get blocks of epoch %v error:%#v\n\n", epochNumber, err) + } + fmt.Printf("blocks of epoch %v:%#v\n\n", epochNumber, blocks) + + blockHash := block.Hash + block, err = client.GetBlockByHash(blockHash) + if err != nil { + fmt.Printf("get block of hash %v error:%#v\n\n", blockHash, err) + } + fmt.Printf("block of hash %v:%#v\n\n", blockHash, block) + + blockSummary, err := client.GetBlockSummaryByEpoch(types.NewEpochNumber(epochNumber)) + if err != nil { + fmt.Printf("get block summary of epoch %v error:%#v\n\n", epochNumber, err) + } + fmt.Printf("block summary of epoch %v:%#v\n\n", epochNumber, blockSummary) + + blockSummary, err = client.GetBlockSummaryByHash(blockHash) + if err != nil { + fmt.Printf("get block summary of block hash %v error:%#v\n\n", blockHash, err) + } + fmt.Printf("block summary of block hash %v:%#v\n\n", blockHash, blockSummary) + + contractAddr := *types.NewAddress("0xa70ddf9b9750c575db453eea6a041f4c8536785a") + code, err := client.GetCode(contractAddr) + if err != nil { + fmt.Printf("get code of address %v err: %v", contractAddr, err) + } + fmt.Printf("get code of address %v:%#v\n\n", contractAddr, code) + + txhash := types.Hash("0x2234bb87229cf36481fdd58f632d2b5f573a62a968eb1fd341e98905e50c81e8") + tx, err := client.GetTransactionByHash(txhash) + if err != nil { + fmt.Printf("get Transaction By Hash %v error:%v\n\n", txhash, err) + } + fmt.Printf("get Transaction By Hash %v:%#v\n\n", txhash, tx) + + receipt, err := client.GetTransactionReceipt(txhash) + if err != nil { + fmt.Printf("transaction receipt of txhash %v error:%v\n\n", txhash, err) + } + fmt.Printf("transaction receipt of txhash %v:%#v\n\n", txhash, receipt) + + rawtx := signTx(client) + txhash, err = client.SendRawTransaction(rawtx) + if err != nil { + fmt.Printf("send Signed Transaction result error :%#v\n\n", err) + } + fmt.Printf("send Signed Transaction result :%#v\n\n", txhash) + if err == nil { + tx = waitTxBePacked(client, txhash) + } + time.Sleep(10 * time.Second) + + //send transaction + utx, err := client.CreateUnsignedTransaction(types.Address("0x19f4bcf113e0b896d9b34294fd3da86b4adf0302"), types.Address("0x1cad0b19bb29d4674531d6f115237e16afce377d"), types.NewBigInt(1000000), nil) + if err != nil { + panic(err) + } + fmt.Printf("creat a new unsigned transaction %+v\n\n", utx) + txhash, err = client.SendTransaction(utx) + if err != nil { + fmt.Printf("send transaction error: %v\n\n", err) + } + fmt.Printf("send transaction done, tx hash is: %v\n\n", txhash) + if err == nil { + tx = waitTxBePacked(client, txhash) + } + time.Sleep(10 * time.Second) + + blockHash = *tx.BlockHash + risk, err := client.GetBlockConfirmRiskByHash(blockHash) + if err != nil { + fmt.Printf("get risk of block %v error: %v\n", blockHash, err) + } + fmt.Printf("get risk of block %v : %v\n", blockHash, risk) + + rate, err := client.GetBlockRevertRateByHash(blockHash) + if err != nil { + fmt.Printf("get revert rate of block %v error: %v\n", blockHash, err) + } + fmt.Printf("get revert rate of block %v : %v\n", blockHash, rate) + + b := new(types.Block) + err = client.CallRPC(b, "cfx_getBlockByHash", "0x6d78977bf3882baf55ade9ffd4682754c66228bd42a6da4d2b5666544fe179bc", false) + if err != nil { + fmt.Printf("use CallRPC get block by hash error:%+v\n\n", err) + } + fmt.Printf("use CallRPC get block by hash result:%+v\n\n", b) +} + +func signTx(client *sdk.Client) []byte { + unSignedTx := types.UnsignedTransaction{ + UnsignedTransactionBase: types.UnsignedTransactionBase{ + From: types.NewAddress("0x19f4bcf113e0b896d9b34294fd3da86b4adf0302"), + Value: types.NewBigInt(100), + }, + To: types.NewAddress("0x10f4bcf113e0b896d9b34294fd3da86b4adf0302"), + } + err := client.ApplyUnsignedTransactionDefault(&unSignedTx) + if err != nil { + panic(err) + } + + signedTx, err := am.SignAndEcodeTransactionWithPassphrase(unSignedTx, "hello") + if err != nil { + panic(err) + } + fmt.Printf("signed tx %+v result:\n0x%x\n\n", unSignedTx, signedTx) + return signedTx +} + +func waitTxBePacked(client *sdk.Client, txhash types.Hash) *types.Transaction { + var tx *types.Transaction + var err error + for { + time.Sleep(time.Duration(1) * time.Second) + tx, err = client.GetTransactionByHash(txhash) + if err != nil { + panic(err) + } + if tx.Status != nil { + fmt.Printf("transaction is packed:%+v\n\n", tx) + break + } + } + return tx +} From 0a8bb6e0e65e4809b09b5e80fb7c3fd2b6991e3f Mon Sep 17 00:00:00 2001 From: Dayong Wang Date: Tue, 12 May 2020 18:29:00 +0800 Subject: [PATCH 4/5] update api.md --- api.md | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/api.md b/api.md index 1ced65c..62f5feb 100644 --- a/api.md +++ b/api.md @@ -183,6 +183,16 @@ func NewClient(nodeURL string) (*Client, error) ``` NewClient creates a new instance of Client with specified conflux node url. +#### func NewClientWithRetry + +```go +func NewClientWithRetry(nodeURL string, retryCount int, retryInterval time.Duration) (*Client, error) +``` +NewClientWithRetry creates a retryable new instance of Client with specified +conflux node url and retry options. + +the retryInterval will be set to 1 second if pass 0 + #### func (*Client) ApplyUnsignedTransactionDefault ```go @@ -433,6 +443,10 @@ Call calls to the contract method with args and fills the excuted result to the the resultPtr should be a pointer of the method output struct type. +please refer +https://github.com/Conflux-Chain/go-conflux-sdk/blob/master/README.md to get the +mappings of solidity types to go types + #### func (*Contract) DecodeEvent ```go @@ -440,17 +454,25 @@ func (contract *Contract) DecodeEvent(out interface{}, event string, log types.L ``` DecodeEvent unpacks a retrieved log into the provided output structure. +please refer +https://github.com/Conflux-Chain/go-conflux-sdk/blob/master/README.md to get the +mappings of solidity types to go types + #### func (*Contract) GetData ```go func (contract *Contract) GetData(method string, args ...interface{}) ([]byte, error) ``` -GetData packs the given method name to conform the ABI of the contract "c". -Method call's data will consist of method_id, args0, arg1, ... argN. Method id -consists of 4 bytes and arguments are all 32 bytes. Method ids are created from -the first 4 bytes of the hash of the methods string signature. (signature = +GetData packs the given method name to conform the ABI of the contract. Method +call's data will consist of method_id, args0, arg1, ... argN. Method id consists +of 4 bytes and arguments are all 32 bytes. Method ids are created from the first +4 bytes of the hash of the methods string signature. (signature = baz(uint32,string32)) +please refer +https://github.com/Conflux-Chain/go-conflux-sdk/blob/master/README.md to get the +mappings of solidity types to go types + #### func (*Contract) SendTransaction ```go @@ -459,6 +481,10 @@ func (contract *Contract) SendTransaction(option *types.ContractMethodSendOption SendTransaction sends a transaction to the contract method with args and returns its transaction hash +please refer +https://github.com/Conflux-Chain/go-conflux-sdk/blob/master/README.md to get the +mappings of solidity types to go types + ### type ContractDeployResult ```go From 865275d49603846691882ebd98ed4f20c02d7601 Mon Sep 17 00:00:00 2001 From: Dayong Wang Date: Tue, 12 May 2020 19:13:47 +0800 Subject: [PATCH 5/5] fix bug --- client.go | 1 - 1 file changed, 1 deletion(-) diff --git a/client.go b/client.go index 10ec4bd..83ece4a 100644 --- a/client.go +++ b/client.go @@ -77,7 +77,6 @@ func (r *rpcClientWithRetry) Call(resultPtr interface{}, method string, args ... } remain := r.retryCount - remain-- for { err = r.inner.Call(resultPtr, method, args...) if err == nil {