diff options
author | Péter Szilágyi <peterke@gmail.com> | 2016-12-22 19:49:16 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-22 19:49:16 +0800 |
commit | 115364b0a9838263c77fe195d7f586c8a295dad3 (patch) | |
tree | 7dab84f57fcd372389377df4070ea057922e1d21 | |
parent | 6d15d00ac4b5f162737a27dfa6f8e9976383776e (diff) | |
parent | 12c964b2b7c70949ae5a8c54cf73be7bbd8c97b4 (diff) | |
download | dexon-115364b0a9838263c77fe195d7f586c8a295dad3.tar.gz dexon-115364b0a9838263c77fe195d7f586c8a295dad3.tar.zst dexon-115364b0a9838263c77fe195d7f586c8a295dad3.zip |
Merge pull request #3475 from fjl/rpc-hex-improvements
rpc: remove HexBytes, HexNumber
-rw-r--r-- | eth/api.go | 32 | ||||
-rw-r--r-- | eth/bind.go | 20 | ||||
-rw-r--r-- | internal/ethapi/api.go | 478 | ||||
-rw-r--r-- | internal/jsre/jsre.go | 2 | ||||
-rw-r--r-- | internal/jsre/pretty.go | 6 | ||||
-rw-r--r-- | les/backend.go | 5 | ||||
-rw-r--r-- | node/api.go | 13 | ||||
-rw-r--r-- | rpc/json.go | 67 | ||||
-rw-r--r-- | rpc/types.go | 115 | ||||
-rw-r--r-- | rpc/types_test.go | 95 | ||||
-rw-r--r-- | whisper/shhapi/api.go | 17 | ||||
-rw-r--r-- | whisper/shhapi/api_test.go | 4 | ||||
-rw-r--r-- | whisper/whisperv2/api.go | 70 |
13 files changed, 287 insertions, 637 deletions
diff --git a/eth/api.go b/eth/api.go index 2cc9c843d..6010d149c 100644 --- a/eth/api.go +++ b/eth/api.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/ethash" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -69,8 +70,8 @@ func (s *PublicEthereumAPI) Coinbase() (common.Address, error) { } // Hashrate returns the POW hashrate -func (s *PublicEthereumAPI) Hashrate() *rpc.HexNumber { - return rpc.NewHexNumber(s.e.Miner().HashRate()) +func (s *PublicEthereumAPI) Hashrate() hexutil.Uint64 { + return hexutil.Uint64(s.e.Miner().HashRate()) } // PublicMinerAPI provides an API to control the miner. @@ -95,8 +96,8 @@ func (s *PublicMinerAPI) Mining() bool { // SubmitWork can be used by external miner to submit their POW solution. It returns an indication if the work was // accepted. Note, this is not an indication if the provided work was valid! -func (s *PublicMinerAPI) SubmitWork(nonce rpc.HexNumber, solution, digest common.Hash) bool { - return s.agent.SubmitWork(nonce.Uint64(), digest, solution) +func (s *PublicMinerAPI) SubmitWork(nonce hexutil.Uint64, solution, digest common.Hash) bool { + return s.agent.SubmitWork(uint64(nonce), digest, solution) } // GetWork returns a work package for external miner. The work package consists of 3 strings @@ -119,8 +120,8 @@ func (s *PublicMinerAPI) GetWork() (work [3]string, err error) { // SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined // hash rate of all miners which submit work through this node. It accepts the miner hash rate and an identifier which // must be unique between nodes. -func (s *PublicMinerAPI) SubmitHashrate(hashrate rpc.HexNumber, id common.Hash) bool { - s.agent.SubmitHashrate(id, hashrate.Uint64()) +func (s *PublicMinerAPI) SubmitHashrate(hashrate hexutil.Uint64, id common.Hash) bool { + s.agent.SubmitHashrate(id, uint64(hashrate)) return true } @@ -137,18 +138,15 @@ func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI { // Start the miner with the given number of threads. If threads is nil the number of // workers started is equal to the number of logical CPU's that are usable by this process. -func (s *PrivateMinerAPI) Start(threads *rpc.HexNumber) (bool, error) { +func (s *PrivateMinerAPI) Start(threads *hexutil.Uint) (bool, error) { s.e.StartAutoDAG() - + var err error if threads == nil { - threads = rpc.NewHexNumber(runtime.NumCPU()) - } - - err := s.e.StartMining(threads.Int()) - if err == nil { - return true, nil + err = s.e.StartMining(runtime.NumCPU()) + } else { + err = s.e.StartMining(int(*threads)) } - return false, err + return err == nil, err } // Stop the miner @@ -166,8 +164,8 @@ func (s *PrivateMinerAPI) SetExtra(extra string) (bool, error) { } // SetGasPrice sets the minimum accepted gas price for the miner. -func (s *PrivateMinerAPI) SetGasPrice(gasPrice rpc.HexNumber) bool { - s.e.Miner().SetGasPrice(gasPrice.BigInt()) +func (s *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { + s.e.Miner().SetGasPrice((*big.Int)(&gasPrice)) return true } diff --git a/eth/bind.go b/eth/bind.go index 747965d37..a9864b367 100644 --- a/eth/bind.go +++ b/eth/bind.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/rlp" @@ -83,16 +84,16 @@ func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs { args := ethapi.CallArgs{ To: msg.To, From: msg.From, - Data: common.ToHex(msg.Data), + Data: msg.Data, } if msg.Gas != nil { - args.Gas = *rpc.NewHexNumber(msg.Gas) + args.Gas = hexutil.Big(*msg.Gas) } if msg.GasPrice != nil { - args.GasPrice = *rpc.NewHexNumber(msg.GasPrice) + args.GasPrice = hexutil.Big(*msg.GasPrice) } if msg.Value != nil { - args.Value = *rpc.NewHexNumber(msg.Value) + args.Value = hexutil.Big(*msg.Value) } return args } @@ -106,9 +107,12 @@ func toBlockNumber(num *big.Int) rpc.BlockNumber { // PendingAccountNonce implements bind.ContractTransactor retrieving the current // pending nonce associated with an account. -func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { +func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (nonce uint64, err error) { out, err := b.txapi.GetTransactionCount(ctx, account, rpc.PendingBlockNumber) - return out.Uint64(), err + if out != nil { + nonce = uint64(*out) + } + return nonce, err } // SuggestGasPrice implements bind.ContractTransactor retrieving the currently @@ -124,13 +128,13 @@ func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) // should provide a basis for setting a reasonable default. func (b *ContractBackend) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (*big.Int, error) { out, err := b.bcapi.EstimateGas(ctx, toCallArgs(msg)) - return out.BigInt(), err + return out.ToInt(), err } // SendTransaction implements bind.ContractTransactor injects the transaction // into the pending pool for execution. func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { raw, _ := rlp.EncodeToBytes(tx) - _, err := b.txapi.SendRawTransaction(ctx, common.ToHex(raw)) + _, err := b.txapi.SendRawTransaction(ctx, raw) return err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 607df6b0c..b84bba516 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -19,7 +19,6 @@ package ethapi import ( "bytes" "encoding/hex" - "encoding/json" "fmt" "math/big" "strings" @@ -44,7 +43,7 @@ import ( "golang.org/x/net/context" ) -const defaultGas = uint64(90000) +const defaultGas = 90000 // PublicEthereumAPI provides an API to access Ethereum related information. // It offers only methods that operate on public data that is freely available to anyone. @@ -63,8 +62,8 @@ func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*big.Int, error) { } // ProtocolVersion returns the current Ethereum protocol version this node supports -func (s *PublicEthereumAPI) ProtocolVersion() *rpc.HexNumber { - return rpc.NewHexNumber(s.b.ProtocolVersion()) +func (s *PublicEthereumAPI) ProtocolVersion() hexutil.Uint { + return hexutil.Uint(s.b.ProtocolVersion()) } // Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not @@ -83,11 +82,11 @@ func (s *PublicEthereumAPI) Syncing() (interface{}, error) { } // Otherwise gather the block sync stats return map[string]interface{}{ - "startingBlock": rpc.NewHexNumber(progress.StartingBlock), - "currentBlock": rpc.NewHexNumber(progress.CurrentBlock), - "highestBlock": rpc.NewHexNumber(progress.HighestBlock), - "pulledStates": rpc.NewHexNumber(progress.PulledStates), - "knownStates": rpc.NewHexNumber(progress.KnownStates), + "startingBlock": hexutil.Uint64(progress.StartingBlock), + "currentBlock": hexutil.Uint64(progress.CurrentBlock), + "highestBlock": hexutil.Uint64(progress.HighestBlock), + "pulledStates": hexutil.Uint64(progress.PulledStates), + "knownStates": hexutil.Uint64(progress.KnownStates), }, nil } @@ -129,11 +128,11 @@ func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransac } // Status returns the number of pending and queued transaction in the pool. -func (s *PublicTxPoolAPI) Status() map[string]*rpc.HexNumber { +func (s *PublicTxPoolAPI) Status() map[string]hexutil.Uint { pending, queue := s.b.Stats() - return map[string]*rpc.HexNumber{ - "pending": rpc.NewHexNumber(pending), - "queued": rpc.NewHexNumber(queue), + return map[string]hexutil.Uint{ + "pending": hexutil.Uint(pending), + "queued": hexutil.Uint(queue), } } @@ -238,13 +237,14 @@ func (s *PrivateAccountAPI) ImportRawKey(privkey string, password string) (commo // UnlockAccount will unlock the account associated with the given address with // the given password for duration seconds. If duration is nil it will use a // default of 300 seconds. It returns an indication if the account was unlocked. -func (s *PrivateAccountAPI) UnlockAccount(addr common.Address, password string, duration *rpc.HexNumber) (bool, error) { +func (s *PrivateAccountAPI) UnlockAccount(addr common.Address, password string, duration *hexutil.Uint) (bool, error) { + var d time.Duration if duration == nil { - duration = rpc.NewHexNumber(300) + d = 300 * time.Second + } else { + d = time.Duration(*duration) * time.Second } - a := accounts.Account{Address: addr} - d := time.Duration(duration.Int64()) * time.Second - if err := s.am.TimedUnlock(a, password, d); err != nil { + if err := s.am.TimedUnlock(accounts.Account{Address: addr}, password, d); err != nil { return false, err } return true, nil @@ -259,27 +259,10 @@ func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool { // tries to sign it with the key associated with args.To. If the given passwd isn't // able to decrypt the key it fails. func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs, passwd string) (common.Hash, error) { - var err error - args, err = prepareSendTxArgs(ctx, args, s.b) - if err != nil { + if err := args.setDefaults(ctx, s.b); err != nil { return common.Hash{}, err } - - if args.Nonce == nil { - nonce, err := s.b.GetPoolNonce(ctx, args.From) - if err != nil { - return common.Hash{}, err - } - args.Nonce = rpc.NewHexNumber(nonce) - } - - var tx *types.Transaction - if args.To == nil { - tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } else { - tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } - + tx := args.toTransaction() signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) signature, err := s.am.SignWithPassphrase(args.From, passwd, signer.Hash(tx).Bytes()) if err != nil { @@ -399,15 +382,15 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash comm // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true // all transactions in the block are returned in full detail, otherwise only the transaction hash is returned. -func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) (map[string]interface{}, error) { +func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { block, err := s.b.BlockByNumber(ctx, blockNr) if block != nil { uncles := block.Uncles() - if index.Int() < 0 || index.Int() >= len(uncles) { - glog.V(logger.Debug).Infof("uncle block on index %d not found for block #%d", index.Int(), blockNr) + if index >= hexutil.Uint(len(uncles)) { + glog.V(logger.Debug).Infof("uncle block on index %d not found for block #%d", index, blockNr) return nil, nil } - block = types.NewBlockWithHeader(uncles[index.Int()]) + block = types.NewBlockWithHeader(uncles[index]) return s.rpcOutputBlock(block, false, false) } return nil, err @@ -415,32 +398,34 @@ func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, // GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. When fullTx is true // all transactions in the block are returned in full detail, otherwise only the transaction hash is returned. -func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) (map[string]interface{}, error) { +func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { block, err := s.b.GetBlock(ctx, blockHash) if block != nil { uncles := block.Uncles() - if index.Int() < 0 || index.Int() >= len(uncles) { - glog.V(logger.Debug).Infof("uncle block on index %d not found for block %s", index.Int(), blockHash.Hex()) + if index >= hexutil.Uint(len(uncles)) { + glog.V(logger.Debug).Infof("uncle block on index %d not found for block %s", index, blockHash.Hex()) return nil, nil } - block = types.NewBlockWithHeader(uncles[index.Int()]) + block = types.NewBlockWithHeader(uncles[index]) return s.rpcOutputBlock(block, false, false) } return nil, err } // GetUncleCountByBlockNumber returns number of uncles in the block for the given block number -func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *rpc.HexNumber { +func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return rpc.NewHexNumber(len(block.Uncles())) + n := hexutil.Uint(len(block.Uncles())) + return &n } return nil } // GetUncleCountByBlockHash returns number of uncles in the block for the given block hash -func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *rpc.HexNumber { +func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { - return rpc.NewHexNumber(len(block.Uncles())) + n := hexutil.Uint(len(block.Uncles())) + return &n } return nil } @@ -497,10 +482,10 @@ func (m callmsg) Data() []byte { return m.data } type CallArgs struct { From common.Address `json:"from"` To *common.Address `json:"to"` - Gas rpc.HexNumber `json:"gas"` - GasPrice rpc.HexNumber `json:"gasPrice"` - Value rpc.HexNumber `json:"value"` - Data string `json:"data"` + Gas hexutil.Big `json:"gas"` + GasPrice hexutil.Big `json:"gasPrice"` + Value hexutil.Big `json:"value"` + Data hexutil.Bytes `json:"data"` } func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) { @@ -525,14 +510,14 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr } // Assemble the CALL invocation - gas, gasPrice := args.Gas.BigInt(), args.GasPrice.BigInt() + gas, gasPrice := args.Gas.ToInt(), args.GasPrice.ToInt() if gas.Cmp(common.Big0) == 0 { gas = big.NewInt(50000000) } if gasPrice.Cmp(common.Big0) == 0 { gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) } - msg := types.NewMessage(addr, args.To, 0, args.Value.BigInt(), gas, gasPrice, common.FromHex(args.Data), false) + msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false) // Execute the call and return vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header) @@ -558,9 +543,9 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr r } // EstimateGas returns an estimate of the amount of gas needed to execute the given transaction. -func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*rpc.HexNumber, error) { +func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) { _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber) - return rpc.NewHexNumber(gas), err + return (*hexutil.Big)(gas), err } // ExecutionResult groups all structured logs emitted by the EVM @@ -622,7 +607,7 @@ func FormatLogs(structLogs []vm.StructLog) []StructLogRes { func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { head := b.Header() // copies the header once fields := map[string]interface{}{ - "number": rpc.NewHexNumber(head.Number), + "number": (*hexutil.Big)(head.Number), "hash": b.Hash(), "parentHash": head.ParentHash, "nonce": head.Nonce, @@ -631,13 +616,13 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx "logsBloom": head.Bloom, "stateRoot": head.Root, "miner": head.Coinbase, - "difficulty": rpc.NewHexNumber(head.Difficulty), - "totalDifficulty": rpc.NewHexNumber(s.b.GetTd(b.Hash())), - "extraData": rpc.HexBytes(head.Extra), - "size": rpc.NewHexNumber(b.Size().Int64()), - "gasLimit": rpc.NewHexNumber(head.GasLimit), - "gasUsed": rpc.NewHexNumber(head.GasUsed), - "timestamp": rpc.NewHexNumber(head.Time), + "difficulty": (*hexutil.Big)(head.Difficulty), + "totalDifficulty": (*hexutil.Big)(s.b.GetTd(b.Hash())), + "extraData": hexutil.Bytes(head.Extra), + "size": hexutil.Uint64(uint64(b.Size().Int64())), + "gasLimit": (*hexutil.Big)(head.GasLimit), + "gasUsed": (*hexutil.Big)(head.GasUsed), + "timestamp": (*hexutil.Big)(head.Time), "transactionsRoot": head.TxHash, "receiptsRoot": head.ReceiptHash, } @@ -677,19 +662,19 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction type RPCTransaction struct { BlockHash common.Hash `json:"blockHash"` - BlockNumber *rpc.HexNumber `json:"blockNumber"` + BlockNumber *hexutil.Big `json:"blockNumber"` From common.Address `json:"from"` - Gas *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` + Gas *hexutil.Big `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` Hash common.Hash `json:"hash"` - Input rpc.HexBytes `json:"input"` - Nonce *rpc.HexNumber `json:"nonce"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` To *common.Address `json:"to"` - TransactionIndex *rpc.HexNumber `json:"transactionIndex"` - Value *rpc.HexNumber `json:"value"` - V *rpc.HexNumber `json:"v"` - R *rpc.HexNumber `json:"r"` - S *rpc.HexNumber `json:"s"` + TransactionIndex hexutil.Uint `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` } // newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation @@ -699,25 +684,25 @@ func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { signer = types.NewEIP155Signer(tx.ChainId()) } from, _ := types.Sender(signer, tx) - v, r, s := types.SignatureValues(signer, tx) + v, r, s := tx.RawSignatureValues() return &RPCTransaction{ From: from, - Gas: rpc.NewHexNumber(tx.Gas()), - GasPrice: rpc.NewHexNumber(tx.GasPrice()), + Gas: (*hexutil.Big)(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), Hash: tx.Hash(), - Input: rpc.HexBytes(tx.Data()), - Nonce: rpc.NewHexNumber(tx.Nonce()), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), To: tx.To(), - Value: rpc.NewHexNumber(tx.Value()), - V: rpc.NewHexNumber(v), - R: rpc.NewHexNumber(r), - S: rpc.NewHexNumber(s), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), } } // newRPCTransaction returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) { - if txIndex >= 0 && txIndex < len(b.Transactions()) { +func newRPCTransactionFromBlockIndex(b *types.Block, txIndex uint) (*RPCTransaction, error) { + if txIndex < uint(len(b.Transactions())) { tx := b.Transactions()[txIndex] var signer types.Signer = types.FrontierSigner{} if tx.Protected() { @@ -727,19 +712,19 @@ func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransacti v, r, s := tx.RawSignatureValues() return &RPCTransaction{ BlockHash: b.Hash(), - BlockNumber: rpc.NewHexNumber(b.Number()), + BlockNumber: (*hexutil.Big)(b.Number()), From: from, - Gas: rpc.NewHexNumber(tx.Gas()), - GasPrice: rpc.NewHexNumber(tx.GasPrice()), + Gas: (*hexutil.Big)(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), Hash: tx.Hash(), - Input: rpc.HexBytes(tx.Data()), - Nonce: rpc.NewHexNumber(tx.Nonce()), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), To: tx.To(), - TransactionIndex: rpc.NewHexNumber(txIndex), - Value: rpc.NewHexNumber(tx.Value()), - V: rpc.NewHexNumber(v), - R: rpc.NewHexNumber(r), - S: rpc.NewHexNumber(s), + TransactionIndex: hexutil.Uint(txIndex), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), }, nil } @@ -747,8 +732,8 @@ func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransacti } // newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. -func newRPCRawTransactionFromBlockIndex(b *types.Block, txIndex int) (rpc.HexBytes, error) { - if txIndex >= 0 && txIndex < len(b.Transactions()) { +func newRPCRawTransactionFromBlockIndex(b *types.Block, txIndex uint) (hexutil.Bytes, error) { + if txIndex < uint(len(b.Transactions())) { tx := b.Transactions()[txIndex] return rlp.EncodeToBytes(tx) } @@ -760,7 +745,7 @@ func newRPCRawTransactionFromBlockIndex(b *types.Block, txIndex int) (rpc.HexByt func newRPCTransaction(b *types.Block, txHash common.Hash) (*RPCTransaction, error) { for idx, tx := range b.Transactions() { if tx.Hash() == txHash { - return newRPCTransactionFromBlockIndex(b, idx) + return newRPCTransactionFromBlockIndex(b, uint(idx)) } } @@ -796,55 +781,57 @@ func getTransaction(chainDb ethdb.Database, b Backend, txHash common.Hash) (*typ } // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. -func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *rpc.HexNumber { +func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return rpc.NewHexNumber(len(block.Transactions())) + n := hexutil.Uint(len(block.Transactions())) + return &n } return nil } // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. -func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *rpc.HexNumber { +func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { - return rpc.NewHexNumber(len(block.Transactions())) + n := hexutil.Uint(len(block.Transactions())) + return &n } return nil } // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) (*RPCTransaction, error) { +func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (*RPCTransaction, error) { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block, index.Int()) + return newRPCTransactionFromBlockIndex(block, uint(index)) } return nil, nil } // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) (*RPCTransaction, error) { +func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (*RPCTransaction, error) { if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block, index.Int()) + return newRPCTransactionFromBlockIndex(block, uint(index)) } return nil, nil } // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. -func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) (rpc.HexBytes, error) { +func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (hexutil.Bytes, error) { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCRawTransactionFromBlockIndex(block, index.Int()) + return newRPCRawTransactionFromBlockIndex(block, uint(index)) } return nil, nil } // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. -func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) (rpc.HexBytes, error) { +func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (hexutil.Bytes, error) { if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { - return newRPCRawTransactionFromBlockIndex(block, index.Int()) + return newRPCRawTransactionFromBlockIndex(block, uint(index)) } return nil, nil } // GetTransactionCount returns the number of transactions the given address has sent for the given block number -func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*rpc.HexNumber, error) { +func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) { state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) if state == nil || err != nil { return nil, err @@ -853,7 +840,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr if err != nil { return nil, err } - return rpc.NewHexNumber(nonce), nil + return (*hexutil.Uint64)(&nonce), nil } // getTransactionBlockData fetches the meta data for the given transaction from the chain database. This is useful to @@ -909,7 +896,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, txH } // GetRawTransactionByHash returns the bytes of the transaction for the given hash. -func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, txHash common.Hash) (rpc.HexBytes, error) { +func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, txHash common.Hash) (hexutil.Bytes, error) { var tx *types.Transaction var err error @@ -950,15 +937,15 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma from, _ := types.Sender(signer, tx) fields := map[string]interface{}{ - "root": rpc.HexBytes(receipt.PostState), + "root": hexutil.Bytes(receipt.PostState), "blockHash": txBlock, - "blockNumber": rpc.NewHexNumber(blockIndex), + "blockNumber": hexutil.Uint64(blockIndex), "transactionHash": txHash, - "transactionIndex": rpc.NewHexNumber(index), + "transactionIndex": hexutil.Uint64(index), "from": from, "to": tx.To(), - "gasUsed": rpc.NewHexNumber(receipt.GasUsed), - "cumulativeGasUsed": rpc.NewHexNumber(receipt.CumulativeGasUsed), + "gasUsed": (*hexutil.Big)(receipt.GasUsed), + "cumulativeGasUsed": (*hexutil.Big)(receipt.CumulativeGasUsed), "contractAddress": nil, "logs": receipt.Logs, "logsBloom": receipt.Bloom, @@ -988,32 +975,46 @@ func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transacti type SendTxArgs struct { From common.Address `json:"from"` To *common.Address `json:"to"` - Gas *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` - Value *rpc.HexNumber `json:"value"` - Data string `json:"data"` - Nonce *rpc.HexNumber `json:"nonce"` + Gas *hexutil.Big `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + Value *hexutil.Big `json:"value"` + Data hexutil.Bytes `json:"data"` + Nonce *hexutil.Uint64 `json:"nonce"` } // prepareSendTxArgs is a helper function that fills in default values for unspecified tx fields. -func prepareSendTxArgs(ctx context.Context, args SendTxArgs, b Backend) (SendTxArgs, error) { +func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { if args.Gas == nil { - args.Gas = rpc.NewHexNumber(defaultGas) + args.Gas = (*hexutil.Big)(big.NewInt(defaultGas)) } if args.GasPrice == nil { price, err := b.SuggestPrice(ctx) if err != nil { - return args, err + return err } - args.GasPrice = rpc.NewHexNumber(price) + args.GasPrice = (*hexutil.Big)(price) } if args.Value == nil { - args.Value = rpc.NewHexNumber(0) + args.Value = new(hexutil.Big) + } + if args.Nonce == nil { + nonce, err := b.GetPoolNonce(ctx, args.From) + if err != nil { + return err + } + args.Nonce = (*hexutil.Uint64)(&nonce) + } + return nil +} + +func (args *SendTxArgs) toTransaction() *types.Transaction { + if args.To == nil { + return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), args.Data) } - return args, nil + return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), args.Data) } -// submitTransaction is a helper function that submits tx to txPool and creates a log entry. +// submitTransaction is a helper function that submits tx to txPool and logs a message. func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signature []byte) (common.Hash, error) { signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number()) @@ -1040,27 +1041,10 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, si // SendTransaction creates a transaction for the given argument, sign it and submit it to the // transaction pool. func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) { - var err error - args, err = prepareSendTxArgs(ctx, args, s.b) - if err != nil { + if err := args.setDefaults(ctx, s.b); err != nil { return common.Hash{}, err } - - if args.Nonce == nil { - nonce, err := s.b.GetPoolNonce(ctx, args.From) - if err != nil { - return common.Hash{}, err - } - args.Nonce = rpc.NewHexNumber(nonce) - } - - var tx *types.Transaction - if args.To == nil { - tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } else { - tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } - + tx := args.toTransaction() signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) signature, err := s.b.AccountManager().SignEthereum(args.From, signer.Hash(tx).Bytes()) if err != nil { @@ -1072,9 +1056,9 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen // SendRawTransaction will add the signed transaction to the transaction pool. // The sender is responsible for signing the transaction and using the correct nonce. -func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx string) (string, error) { +func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (string, error) { tx := new(types.Transaction) - if err := rlp.DecodeBytes(common.FromHex(encodedTx), tx); err != nil { + if err := rlp.DecodeBytes(encodedTx, tx); err != nil { return "", err } @@ -1107,153 +1091,28 @@ func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) return s.b.AccountManager().SignEthereum(addr, signHash(data)) } -// SignTransactionArgs represents the arguments to sign a transaction. -type SignTransactionArgs struct { - From common.Address - To *common.Address - Nonce *rpc.HexNumber - Value *rpc.HexNumber - Gas *rpc.HexNumber - GasPrice *rpc.HexNumber - Data string - - BlockNumber int64 -} - -// Tx is a helper object for argument and return values -type Tx struct { - tx *types.Transaction - - To *common.Address `json:"to"` - From common.Address `json:"from"` - Nonce *rpc.HexNumber `json:"nonce"` - Value *rpc.HexNumber `json:"value"` - Data string `json:"data"` - GasLimit *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` - Hash common.Hash `json:"hash"` -} - -// UnmarshalJSON parses JSON data into tx. -func (tx *Tx) UnmarshalJSON(b []byte) (err error) { - req := struct { - To *common.Address `json:"to"` - From common.Address `json:"from"` - Nonce *rpc.HexNumber `json:"nonce"` - Value *rpc.HexNumber `json:"value"` - Data string `json:"data"` - GasLimit *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` - Hash common.Hash `json:"hash"` - }{} - - if err := json.Unmarshal(b, &req); err != nil { - return err - } - - tx.To = req.To - tx.From = req.From - tx.Nonce = req.Nonce - tx.Value = req.Value - tx.Data = req.Data - tx.GasLimit = req.GasLimit - tx.GasPrice = req.GasPrice - tx.Hash = req.Hash - - data := common.Hex2Bytes(tx.Data) - - if tx.Nonce == nil { - return fmt.Errorf("need nonce") - } - if tx.Value == nil { - tx.Value = rpc.NewHexNumber(0) - } - if tx.GasLimit == nil { - tx.GasLimit = rpc.NewHexNumber(0) - } - if tx.GasPrice == nil { - tx.GasPrice = rpc.NewHexNumber(int64(50000000000)) - } - - if req.To == nil { - tx.tx = types.NewContractCreation(tx.Nonce.Uint64(), tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data) - } else { - tx.tx = types.NewTransaction(tx.Nonce.Uint64(), *tx.To, tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data) - } - - return nil -} - // SignTransactionResult represents a RLP encoded signed transaction. type SignTransactionResult struct { - Raw string `json:"raw"` - Tx *Tx `json:"tx"` -} - -func newTx(t *types.Transaction) *Tx { - var signer types.Signer = types.HomesteadSigner{} - if t.Protected() { - signer = types.NewEIP155Signer(t.ChainId()) - } - - from, _ := types.Sender(signer, t) - return &Tx{ - tx: t, - To: t.To(), - From: from, - Value: rpc.NewHexNumber(t.Value()), - Nonce: rpc.NewHexNumber(t.Nonce()), - Data: "0x" + common.Bytes2Hex(t.Data()), - GasLimit: rpc.NewHexNumber(t.Gas()), - GasPrice: rpc.NewHexNumber(t.GasPrice()), - Hash: t.Hash(), - } + Raw hexutil.Bytes `json:"raw"` + Tx *types.Transaction `json:"tx"` } // SignTransaction will sign the given transaction with the from account. // The node needs to have the private key of the account corresponding with // the given from address and it needs to be unlocked. -func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args SignTransactionArgs) (*SignTransactionResult, error) { - if args.Gas == nil { - args.Gas = rpc.NewHexNumber(defaultGas) - } - if args.GasPrice == nil { - price, err := s.b.SuggestPrice(ctx) - if err != nil { - return nil, err - } - args.GasPrice = rpc.NewHexNumber(price) - } - if args.Value == nil { - args.Value = rpc.NewHexNumber(0) - } - - if args.Nonce == nil { - nonce, err := s.b.GetPoolNonce(ctx, args.From) - if err != nil { - return nil, err - } - args.Nonce = rpc.NewHexNumber(nonce) - } - - var tx *types.Transaction - if args.To == nil { - tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } else { - tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) +func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args SendTxArgs) (*SignTransactionResult, error) { + if err := args.setDefaults(ctx, s.b); err != nil { + return nil, err } - - signedTx, err := s.sign(args.From, tx) + tx, err := s.sign(args.From, args.toTransaction()) if err != nil { return nil, err } - - data, err := rlp.EncodeToBytes(signedTx) + data, err := rlp.EncodeToBytes(tx) if err != nil { return nil, err } - - return &SignTransactionResult{"0x" + common.Bytes2Hex(data), newTx(signedTx)}, nil + return &SignTransactionResult{data, tx}, nil } // PendingTransactions returns the transactions that are in the transaction pool and have a from address that is one of @@ -1278,9 +1137,16 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err return transactions, nil } -// Resend accepts an existing transaction and a new gas price and limit. It will remove the given transaction from the -// pool and reinsert it with the new gas price and limit. -func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) { +// Resend accepts an existing transaction and a new gas price and limit. It will remove +// the given transaction from the pool and reinsert it with the new gas price and limit. +func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxArgs, gasPrice, gasLimit *hexutil.Big) (common.Hash, error) { + if sendArgs.Nonce == nil { + return common.Hash{}, fmt.Errorf("missing transaction nonce in transaction spec") + } + if err := sendArgs.setDefaults(ctx, s.b); err != nil { + return common.Hash{}, err + } + matchTx := sendArgs.toTransaction() pending, err := s.b.GetPoolTransactions() if err != nil { return common.Hash{}, err @@ -1291,37 +1157,29 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, if p.Protected() { signer = types.NewEIP155Signer(p.ChainId()) } + wantSigHash := signer.Hash(matchTx) - if pFrom, err := types.Sender(signer, p); err == nil && pFrom == tx.From && signer.Hash(p) == signer.Hash(tx.tx) { - if gasPrice == nil { - gasPrice = rpc.NewHexNumber(tx.tx.GasPrice()) - } - if gasLimit == nil { - gasLimit = rpc.NewHexNumber(tx.tx.Gas()) + if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.From && signer.Hash(p) == wantSigHash { + // Match. Re-sign and send the transaction. + if gasPrice != nil { + sendArgs.GasPrice = gasPrice } - - var newTx *types.Transaction - if tx.tx.To() == nil { - newTx = types.NewContractCreation(tx.tx.Nonce(), tx.tx.Value(), gasLimit.BigInt(), gasPrice.BigInt(), tx.tx.Data()) - } else { - newTx = types.NewTransaction(tx.tx.Nonce(), *tx.tx.To(), tx.tx.Value(), gasLimit.BigInt(), gasPrice.BigInt(), tx.tx.Data()) + if gasLimit != nil { + sendArgs.Gas = gasLimit } - - signedTx, err := s.sign(tx.From, newTx) + signedTx, err := s.sign(sendArgs.From, sendArgs.toTransaction()) if err != nil { return common.Hash{}, err } - - s.b.RemoveTx(tx.Hash) + s.b.RemoveTx(p.Hash()) if err = s.b.SendTx(ctx, signedTx); err != nil { return common.Hash{}, err } - return signedTx.Hash(), nil } } - return common.Hash{}, fmt.Errorf("Transaction %#x not found", tx.Hash) + return common.Hash{}, fmt.Errorf("Transaction %#x not found", matchTx.Hash()) } // PublicDebugAPI is the collection of Etheruem APIs exposed over the public @@ -1418,8 +1276,8 @@ func (api *PrivateDebugAPI) ChaindbCompact() error { } // SetHead rewinds the head of the blockchain to a previous block. -func (api *PrivateDebugAPI) SetHead(number rpc.HexNumber) { - api.b.SetHead(uint64(number.Int64())) +func (api *PrivateDebugAPI) SetHead(number hexutil.Uint64) { + api.b.SetHead(uint64(number)) } // PublicNetAPI offers network related RPC methods @@ -1439,8 +1297,8 @@ func (s *PublicNetAPI) Listening() bool { } // PeerCount returns the number of connected peers -func (s *PublicNetAPI) PeerCount() *rpc.HexNumber { - return rpc.NewHexNumber(s.net.PeerCount()) +func (s *PublicNetAPI) PeerCount() hexutil.Uint { + return hexutil.Uint(s.net.PeerCount()) } // Version returns the current ethereum protocol version. diff --git a/internal/jsre/jsre.go b/internal/jsre/jsre.go index 481389304..17b686c6a 100644 --- a/internal/jsre/jsre.go +++ b/internal/jsre/jsre.go @@ -71,7 +71,7 @@ func New(assetPath string, output io.Writer) *JSRE { } go re.runEventLoop() re.Set("loadScript", re.loadScript) - re.Set("inspect", prettyPrintJS) + re.Set("inspect", re.prettyPrintJS) return re } diff --git a/internal/jsre/pretty.go b/internal/jsre/pretty.go index 8fe00cc4c..e096eec23 100644 --- a/internal/jsre/pretty.go +++ b/internal/jsre/pretty.go @@ -73,10 +73,10 @@ func jsErrorString(err error) string { return err.Error() } -func prettyPrintJS(call otto.FunctionCall, w io.Writer) otto.Value { +func (re *JSRE) prettyPrintJS(call otto.FunctionCall) otto.Value { for _, v := range call.ArgumentList { - prettyPrint(call.Otto, v, w) - fmt.Fprintln(w) + prettyPrint(call.Otto, v, re.output) + fmt.Fprintln(re.output) } return otto.UndefinedValue() } diff --git a/les/backend.go b/les/backend.go index 726664227..d21d5a98c 100644 --- a/les/backend.go +++ b/les/backend.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/compiler" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" @@ -135,8 +136,8 @@ func (s *LightDummyAPI) Coinbase() (common.Address, error) { } // Hashrate returns the POW hashrate -func (s *LightDummyAPI) Hashrate() *rpc.HexNumber { - return rpc.NewHexNumber(0) +func (s *LightDummyAPI) Hashrate() hexutil.Uint { + return 0 } // Mining returns an indication if this node is currently mining. diff --git a/node/api.go b/node/api.go index 7c9ad601a..988eff379 100644 --- a/node/api.go +++ b/node/api.go @@ -25,7 +25,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/discover" - "github.com/ethereum/go-ethereum/rpc" "github.com/rcrowley/go-metrics" ) @@ -75,7 +74,7 @@ func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) { } // StartRPC starts the HTTP RPC API server. -func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *string, apis *string) (bool, error) { +func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string) (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -91,7 +90,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *st host = &h } if port == nil { - port = rpc.NewHexNumber(api.node.config.HTTPPort) + port = &api.node.config.HTTPPort } if cors == nil { cors = &api.node.config.HTTPCors @@ -105,7 +104,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *st } } - if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, port.Int()), api.node.rpcAPIs, modules, *cors); err != nil { + if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, port), api.node.rpcAPIs, modules, *cors); err != nil { return false, err } return true, nil @@ -124,7 +123,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) { } // StartWS starts the websocket RPC API server. -func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOrigins *string, apis *string) (bool, error) { +func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -140,7 +139,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOr host = &h } if port == nil { - port = rpc.NewHexNumber(api.node.config.WSPort) + port = &api.node.config.WSPort } if allowedOrigins == nil { allowedOrigins = &api.node.config.WSOrigins @@ -154,7 +153,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOr } } - if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, port.Int()), api.node.rpcAPIs, modules, *allowedOrigins); err != nil { + if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, *allowedOrigins); err != nil { return false, err } return true, nil diff --git a/rpc/json.go b/rpc/json.go index a7053e3f5..ac5a4acd3 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -17,6 +17,7 @@ package rpc import ( + "bytes" "encoding/json" "fmt" "io" @@ -256,8 +257,8 @@ func parseBatchRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error) return requests, true, nil } -// ParseRequestArguments tries to parse the given params (json.RawMessage) with the given types. It returns the parsed -// values or an error when the parsing failed. +// ParseRequestArguments tries to parse the given params (json.RawMessage) with the given +// types. It returns the parsed values or an error when the parsing failed. func (c *jsonCodec) ParseRequestArguments(argTypes []reflect.Type, params interface{}) ([]reflect.Value, Error) { if args, ok := params.(json.RawMessage); !ok { return nil, &invalidParamsError{"Invalid params supplied"} @@ -266,42 +267,42 @@ func (c *jsonCodec) ParseRequestArguments(argTypes []reflect.Type, params interf } } -// parsePositionalArguments tries to parse the given args to an array of values with the given types. -// It returns the parsed values or an error when the args could not be parsed. Missing optional arguments -// are returned as reflect.Zero values. -func parsePositionalArguments(args json.RawMessage, callbackArgs []reflect.Type) ([]reflect.Value, Error) { - params := make([]interface{}, 0, len(callbackArgs)) - for _, t := range callbackArgs { - params = append(params, reflect.New(t).Interface()) +// parsePositionalArguments tries to parse the given args to an array of values with the +// given types. It returns the parsed values or an error when the args could not be +// parsed. Missing optional arguments are returned as reflect.Zero values. +func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, Error) { + // Read beginning of the args array. + dec := json.NewDecoder(bytes.NewReader(rawArgs)) + if tok, _ := dec.Token(); tok != json.Delim('[') { + return nil, &invalidParamsError{"non-array args"} } - - if err := json.Unmarshal(args, ¶ms); err != nil { - return nil, &invalidParamsError{err.Error()} - } - - if len(params) > len(callbackArgs) { - return nil, &invalidParamsError{fmt.Sprintf("too many params, want %d got %d", len(callbackArgs), len(params))} + // Read args. + args := make([]reflect.Value, 0, len(types)) + for i := 0; dec.More(); i++ { + if i >= len(types) { + return nil, &invalidParamsError{fmt.Sprintf("too many arguments, want at most %d", len(types))} + } + argval := reflect.New(types[i]) + if err := dec.Decode(argval.Interface()); err != nil { + return nil, &invalidParamsError{fmt.Sprintf("invalid argument %d: %v", i, err)} + } + if argval.IsNil() && types[i].Kind() != reflect.Ptr { + return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)} + } + args = append(args, argval.Elem()) } - - // assume missing params are null values - for i := len(params); i < len(callbackArgs); i++ { - params = append(params, nil) + // Read end of args array. + if _, err := dec.Token(); err != nil { + return nil, &invalidParamsError{err.Error()} } - - argValues := make([]reflect.Value, len(params)) - for i, p := range params { - // verify that JSON null values are only supplied for optional arguments (ptr types) - if p == nil && callbackArgs[i].Kind() != reflect.Ptr { - return nil, &invalidParamsError{fmt.Sprintf("invalid or missing value for params[%d]", i)} - } - if p == nil { - argValues[i] = reflect.Zero(callbackArgs[i]) - } else { // deref pointers values creates previously with reflect.New - argValues[i] = reflect.ValueOf(p).Elem() + // Set any missing args to nil. + for i := len(args); i < len(types); i++ { + if types[i].Kind() != reflect.Ptr { + return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)} } + args = append(args, reflect.Zero(types[i])) } - - return argValues, nil + return args, nil } // CreateResponse will create a JSON-RPC success response with the given id and reply as result. diff --git a/rpc/types.go b/rpc/types.go index ebe388373..01b95a170 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -17,8 +17,6 @@ package rpc import ( - "bytes" - "encoding/hex" "fmt" "math" "math/big" @@ -123,91 +121,6 @@ type ServerCodec interface { Closed() <-chan interface{} } -// HexNumber serializes a number to hex format using the "%#x" format -type HexNumber big.Int - -// NewHexNumber creates a new hex number instance which will serialize the given val with `%#x` on marshal. -func NewHexNumber(val interface{}) *HexNumber { - if val == nil { - return nil // note, this doesn't catch nil pointers, only passing nil directly! - } - - if v, ok := val.(*big.Int); ok { - if v != nil { - return (*HexNumber)(new(big.Int).Set(v)) - } - return nil - } - - rval := reflect.ValueOf(val) - - var unsigned uint64 - utype := reflect.TypeOf(unsigned) - if t := rval.Type(); t.ConvertibleTo(utype) { - hn := new(big.Int).SetUint64(rval.Convert(utype).Uint()) - return (*HexNumber)(hn) - } - - var signed int64 - stype := reflect.TypeOf(signed) - if t := rval.Type(); t.ConvertibleTo(stype) { - hn := new(big.Int).SetInt64(rval.Convert(stype).Int()) - return (*HexNumber)(hn) - } - - return nil -} - -func (h *HexNumber) UnmarshalJSON(input []byte) error { - length := len(input) - if length >= 2 && input[0] == '"' && input[length-1] == '"' { - input = input[1 : length-1] - } - - hn := (*big.Int)(h) - if _, ok := hn.SetString(string(input), 0); ok { - return nil - } - - return fmt.Errorf("Unable to parse number") -} - -// MarshalJSON serialize the hex number instance to a hex representation. -func (h *HexNumber) MarshalJSON() ([]byte, error) { - if h != nil { - hn := (*big.Int)(h) - if hn.BitLen() == 0 { - return []byte(`"0x0"`), nil - } - return []byte(fmt.Sprintf(`"0x%x"`, hn)), nil - } - return nil, nil -} - -func (h *HexNumber) Int() int { - hn := (*big.Int)(h) - return int(hn.Int64()) -} - -func (h *HexNumber) Int64() int64 { - hn := (*big.Int)(h) - return hn.Int64() -} - -func (h *HexNumber) Uint() uint { - hn := (*big.Int)(h) - return uint(hn.Uint64()) -} - -func (h *HexNumber) Uint64() uint64 { - hn := (*big.Int)(h) - return hn.Uint64() -} - -func (h *HexNumber) BigInt() *big.Int { - return (*big.Int)(h) -} - var ( pendingBlockNumber = big.NewInt(-2) latestBlockNumber = big.NewInt(-1) @@ -274,31 +187,3 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { func (bn BlockNumber) Int64() int64 { return (int64)(bn) } - -// HexBytes JSON-encodes as hex with 0x prefix. -type HexBytes []byte - -func (b HexBytes) MarshalJSON() ([]byte, error) { - result := make([]byte, len(b)*2+4) - copy(result, `"0x`) - hex.Encode(result[3:], b) - result[len(result)-1] = '"' - return result, nil -} - -func (b *HexBytes) UnmarshalJSON(input []byte) error { - if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { - input = input[1 : len(input)-1] - } - if !bytes.HasPrefix(input, []byte("0x")) { - return fmt.Errorf("missing 0x prefix for hex byte array") - } - input = input[2:] - if len(input) == 0 { - *b = nil - return nil - } - *b = make([]byte, len(input)/2) - _, err := hex.Decode(*b, input) - return err -} diff --git a/rpc/types_test.go b/rpc/types_test.go deleted file mode 100644 index 5482557b8..000000000 --- a/rpc/types_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package rpc - -import ( - "bytes" - "encoding/json" - "math/big" - "testing" -) - -func TestNewHexNumber(t *testing.T) { - tests := []interface{}{big.NewInt(123), int64(123), uint64(123), int8(123), uint8(123)} - - for i, v := range tests { - hn := NewHexNumber(v) - if hn == nil { - t.Fatalf("Unable to create hex number instance for tests[%d]", i) - } - if hn.Int64() != 123 { - t.Fatalf("expected %d, got %d on value tests[%d]", 123, hn.Int64(), i) - } - } - - failures := []interface{}{"", nil, []byte{1, 2, 3, 4}} - for i, v := range failures { - hn := NewHexNumber(v) - if hn != nil { - t.Fatalf("Creating a nex number instance of %T should fail (failures[%d])", failures[i], i) - } - } -} - -func TestHexNumberUnmarshalJSON(t *testing.T) { - tests := []string{`"0x4d2"`, "1234", `"1234"`} - for i, v := range tests { - var hn HexNumber - if err := json.Unmarshal([]byte(v), &hn); err != nil { - t.Fatalf("Test %d failed - %s", i, err) - } - - if hn.Int64() != 1234 { - t.Fatalf("Expected %d, got %d for test[%d]", 1234, hn.Int64(), i) - } - } -} - -func TestHexNumberMarshalJSON(t *testing.T) { - hn := NewHexNumber(1234567890) - got, err := json.Marshal(hn) - if err != nil { - t.Fatalf("Unable to marshal hex number - %s", err) - } - - exp := []byte(`"0x499602d2"`) - if bytes.Compare(exp, got) != 0 { - t.Fatalf("Invalid json.Marshal, expected '%s', got '%s'", exp, got) - } -} - -var hexBytesTests = []struct{ in, out []byte }{ - {in: []byte(`"0x"`), out: []byte{}}, - {in: []byte(`"0x00"`), out: []byte{0}}, - {in: []byte(`"0x01ff"`), out: []byte{0x01, 0xFF}}, -} - -func TestHexBytes(t *testing.T) { - for i, test := range hexBytesTests { - var dec HexBytes - if err := json.Unmarshal(test.in, &dec); err != nil { - t.Fatalf("test %d: can't decode: %v", i, err) - } - enc, _ := json.Marshal(HexBytes(test.out)) - if !bytes.Equal(dec, test.out) { - t.Errorf("test %d: wrong decoded value 0x%x", i, dec) - } - if !bytes.Equal(enc, test.in) { - t.Errorf("test %d: wrong encoded value %#q", i, enc) - } - } -} diff --git a/whisper/shhapi/api.go b/whisper/shhapi/api.go index f2597e133..24d54b653 100644 --- a/whisper/shhapi/api.go +++ b/whisper/shhapi/api.go @@ -23,6 +23,7 @@ import ( mathrand "math/rand" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" @@ -72,16 +73,16 @@ func (api *PublicWhisperAPI) Stop() error { } // Version returns the Whisper version this node offers. -func (api *PublicWhisperAPI) Version() (*rpc.HexNumber, error) { +func (api *PublicWhisperAPI) Version() (hexutil.Uint, error) { if api.whisper == nil { - return rpc.NewHexNumber(0), whisperOffLineErr + return 0, whisperOffLineErr } - return rpc.NewHexNumber(api.whisper.Version()), nil + return hexutil.Uint(api.whisper.Version()), nil } // MarkPeerTrusted marks specific peer trusted, which will allow it // to send historic (expired) messages. -func (api *PublicWhisperAPI) MarkPeerTrusted(peerID rpc.HexBytes) error { +func (api *PublicWhisperAPI) MarkPeerTrusted(peerID hexutil.Bytes) error { if api.whisper == nil { return whisperOffLineErr } @@ -92,7 +93,7 @@ func (api *PublicWhisperAPI) MarkPeerTrusted(peerID rpc.HexBytes) error { // data contains parameters (time frame, payment details, etc.), required // by the remote email-like server. Whisper is not aware about the data format, // it will just forward the raw data to the server. -func (api *PublicWhisperAPI) RequestHistoricMessages(peerID rpc.HexBytes, data rpc.HexBytes) error { +func (api *PublicWhisperAPI) RequestHistoricMessages(peerID hexutil.Bytes, data hexutil.Bytes) error { if api.whisper == nil { return whisperOffLineErr } @@ -388,12 +389,12 @@ type PostArgs struct { To string `json:"to"` KeyName string `json:"keyname"` Topic whisperv5.TopicType `json:"topic"` - Padding rpc.HexBytes `json:"padding"` - Payload rpc.HexBytes `json:"payload"` + Padding hexutil.Bytes `json:"padding"` + Payload hexutil.Bytes `json:"payload"` WorkTime uint32 `json:"worktime"` PoW float64 `json:"pow"` FilterID uint32 `json:"filterID"` - PeerID rpc.HexBytes `json:"peerID"` + PeerID hexutil.Bytes `json:"peerID"` } type WhisperFilterArgs struct { diff --git a/whisper/shhapi/api_test.go b/whisper/shhapi/api_test.go index a10e2e476..d2890a9a3 100644 --- a/whisper/shhapi/api_test.go +++ b/whisper/shhapi/api_test.go @@ -39,8 +39,8 @@ func TestBasic(t *testing.T) { t.Fatalf("failed generateFilter: %s.", err) } - if ver.Uint64() != whisperv5.ProtocolVersion { - t.Fatalf("wrong version: %d.", ver.Uint64()) + if uint64(ver) != whisperv5.ProtocolVersion { + t.Fatalf("wrong version: %d.", ver) } mail := api.GetFilterChanges(1) diff --git a/whisper/whisperv2/api.go b/whisper/whisperv2/api.go index 9c9c6a84c..0509453ba 100644 --- a/whisper/whisperv2/api.go +++ b/whisper/whisperv2/api.go @@ -23,8 +23,8 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rpc" ) // PublicWhisperAPI provides the whisper RPC service. @@ -32,7 +32,7 @@ type PublicWhisperAPI struct { w *Whisper messagesMu sync.RWMutex - messages map[int]*whisperFilter + messages map[hexutil.Uint]*whisperFilter } type whisperOfflineError struct{} @@ -46,15 +46,15 @@ var whisperOffLineErr = new(whisperOfflineError) // NewPublicWhisperAPI create a new RPC whisper service. func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI { - return &PublicWhisperAPI{w: w, messages: make(map[int]*whisperFilter)} + return &PublicWhisperAPI{w: w, messages: make(map[hexutil.Uint]*whisperFilter)} } // Version returns the Whisper version this node offers. -func (s *PublicWhisperAPI) Version() (*rpc.HexNumber, error) { +func (s *PublicWhisperAPI) Version() (hexutil.Uint, error) { if s.w == nil { - return rpc.NewHexNumber(0), whisperOffLineErr + return 0, whisperOffLineErr } - return rpc.NewHexNumber(s.w.Version()), nil + return hexutil.Uint(s.w.Version()), nil } // HasIdentity checks if the the whisper node is configured with the private key @@ -84,12 +84,12 @@ type NewFilterArgs struct { } // NewWhisperFilter creates and registers a new message filter to watch for inbound whisper messages. -func (s *PublicWhisperAPI) NewFilter(args NewFilterArgs) (*rpc.HexNumber, error) { +func (s *PublicWhisperAPI) NewFilter(args NewFilterArgs) (hexutil.Uint, error) { if s.w == nil { - return nil, whisperOffLineErr + return 0, whisperOffLineErr } - var id int + var id hexutil.Uint filter := Filter{ To: crypto.ToECDSAPub(common.FromHex(args.To)), From: crypto.ToECDSAPub(common.FromHex(args.From)), @@ -103,23 +103,22 @@ func (s *PublicWhisperAPI) NewFilter(args NewFilterArgs) (*rpc.HexNumber, error) } }, } - - id = s.w.Watch(filter) + id = hexutil.Uint(s.w.Watch(filter)) s.messagesMu.Lock() s.messages[id] = newWhisperFilter(id, s.w) s.messagesMu.Unlock() - return rpc.NewHexNumber(id), nil + return id, nil } // GetFilterChanges retrieves all the new messages matched by a filter since the last retrieval. -func (s *PublicWhisperAPI) GetFilterChanges(filterId rpc.HexNumber) []WhisperMessage { +func (s *PublicWhisperAPI) GetFilterChanges(filterId hexutil.Uint) []WhisperMessage { s.messagesMu.RLock() defer s.messagesMu.RUnlock() - if s.messages[filterId.Int()] != nil { - if changes := s.messages[filterId.Int()].retrieve(); changes != nil { + if s.messages[filterId] != nil { + if changes := s.messages[filterId].retrieve(); changes != nil { return changes } } @@ -127,26 +126,26 @@ func (s *PublicWhisperAPI) GetFilterChanges(filterId rpc.HexNumber) []WhisperMes } // UninstallFilter disables and removes an existing filter. -func (s *PublicWhisperAPI) UninstallFilter(filterId rpc.HexNumber) bool { +func (s *PublicWhisperAPI) UninstallFilter(filterId hexutil.Uint) bool { s.messagesMu.Lock() defer s.messagesMu.Unlock() - if _, ok := s.messages[filterId.Int()]; ok { - delete(s.messages, filterId.Int()) + if _, ok := s.messages[filterId]; ok { + delete(s.messages, filterId) return true } return false } // GetMessages retrieves all the known messages that match a specific filter. -func (s *PublicWhisperAPI) GetMessages(filterId rpc.HexNumber) []WhisperMessage { +func (s *PublicWhisperAPI) GetMessages(filterId hexutil.Uint) []WhisperMessage { // Retrieve all the cached messages matching a specific, existing filter s.messagesMu.RLock() defer s.messagesMu.RUnlock() var messages []*Message - if s.messages[filterId.Int()] != nil { - messages = s.messages[filterId.Int()].messages() + if s.messages[filterId] != nil { + messages = s.messages[filterId].messages() } return returnWhisperMessages(messages) @@ -217,12 +216,12 @@ type WhisperMessage struct { func (args *PostArgs) UnmarshalJSON(data []byte) (err error) { var obj struct { - From string `json:"from"` - To string `json:"to"` - Topics []string `json:"topics"` - Payload string `json:"payload"` - Priority rpc.HexNumber `json:"priority"` - TTL rpc.HexNumber `json:"ttl"` + From string `json:"from"` + To string `json:"to"` + Topics []string `json:"topics"` + Payload string `json:"payload"` + Priority hexutil.Uint64 `json:"priority"` + TTL hexutil.Uint64 `json:"ttl"` } if err := json.Unmarshal(data, &obj); err != nil { @@ -232,8 +231,8 @@ func (args *PostArgs) UnmarshalJSON(data []byte) (err error) { args.From = obj.From args.To = obj.To args.Payload = obj.Payload - args.Priority = obj.Priority.Int64() - args.TTL = obj.TTL.Int64() + args.Priority = int64(obj.Priority) // TODO(gluk256): handle overflow + args.TTL = int64(obj.TTL) // ... here too ... // decode topic strings args.Topics = make([][]byte, len(obj.Topics)) @@ -328,8 +327,8 @@ func (args *NewFilterArgs) UnmarshalJSON(b []byte) (err error) { // whisperFilter is the message cache matching a specific filter, accumulating // inbound messages until the are requested by the client. type whisperFilter struct { - id int // Filter identifier for old message retrieval - ref *Whisper // Whisper reference for old message retrieval + id hexutil.Uint // Filter identifier for old message retrieval + ref *Whisper // Whisper reference for old message retrieval cache []WhisperMessage // Cache of messages not yet polled skip map[common.Hash]struct{} // List of retrieved messages to avoid duplication @@ -348,7 +347,7 @@ func (w *whisperFilter) messages() []*Message { w.update = time.Now() w.skip = make(map[common.Hash]struct{}) - messages := w.ref.Messages(w.id) + messages := w.ref.Messages(int(w.id)) for _, message := range messages { w.skip[message.Hash] = struct{}{} } @@ -388,11 +387,10 @@ func (w *whisperFilter) activity() time.Time { } // newWhisperFilter creates a new serialized, poll based whisper topic filter. -func newWhisperFilter(id int, ref *Whisper) *whisperFilter { +func newWhisperFilter(id hexutil.Uint, ref *Whisper) *whisperFilter { return &whisperFilter{ - id: id, - ref: ref, - + id: id, + ref: ref, update: time.Now(), skip: make(map[common.Hash]struct{}), } |