@ -17,7 +17,6 @@
package ethapi
import (
"bytes"
"context"
"errors"
"fmt"
@ -351,9 +350,9 @@ func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool {
// signTransaction sets defaults and signs the given transaction
// NOTE: the caller needs to ensure that the nonceLock is held, if applicable,
// and release it after the transaction has been submitted to the tx pool
func ( s * PrivateAccountAPI ) signTransaction ( ctx context . Context , args * SendTx Args, passwd string ) ( * types . Transaction , error ) {
func ( s * PrivateAccountAPI ) signTransaction ( ctx context . Context , args * Transaction Args, passwd string ) ( * types . Transaction , error ) {
// Look up the wallet containing the requested signer
account := accounts . Account { Address : args . From }
account := accounts . Account { Address : args . from ( ) }
wallet , err := s . am . Find ( account )
if err != nil {
return nil , err
@ -369,18 +368,18 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *SendTxArg
}
// SendTransaction will create a transaction from the given arguments and
// tries to sign it with the key associated with args.From. If the given passwd isn't
// able to decrypt the key it fails.
func ( s * PrivateAccountAPI ) SendTransaction ( ctx context . Context , args SendTx Args, passwd string ) ( common . Hash , error ) {
// tries to sign it with the key associated with args.From. If the given
// passwd isn't able to decrypt the key it fails.
func ( s * PrivateAccountAPI ) SendTransaction ( ctx context . Context , args Transaction Args, passwd string ) ( common . Hash , error ) {
if args . Nonce == nil {
// Hold the addresse's mutex around signing to prevent concurrent assignment of
// the same nonce to multiple accounts.
s . nonceLock . LockAddr ( args . From )
defer s . nonceLock . UnlockAddr ( args . From )
s . nonceLock . LockAddr ( args . from ( ) )
defer s . nonceLock . UnlockAddr ( args . from ( ) )
}
signed , err := s . signTransaction ( ctx , & args , passwd )
if err != nil {
log . Warn ( "Failed transaction send attempt" , "from" , args . From , "to" , args . To , "value" , args . Value . ToInt ( ) , "err" , err )
log . Warn ( "Failed transaction send attempt" , "from" , args . from ( ) , "to" , args . To , "value" , args . Value . ToInt ( ) , "err" , err )
return common . Hash { } , err
}
return SubmitTransaction ( ctx , s . b , signed )
@ -390,9 +389,12 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
// tries to sign it with the key associated with args.From. If the given passwd isn't
// able to decrypt the key it fails. The transaction is returned in RLP-form, not broadcast
// to other nodes
func ( s * PrivateAccountAPI ) SignTransaction ( ctx context . Context , args SendTx Args, passwd string ) ( * SignTransactionResult , error ) {
func ( s * PrivateAccountAPI ) SignTransaction ( ctx context . Context , args Transaction Args, passwd string ) ( * SignTransactionResult , error ) {
// No need to obtain the noncelock mutex, since we won't be sending this
// tx into the transaction pool, but right back to the user
if args . From == nil {
return nil , fmt . Errorf ( "sender not specified" )
}
if args . Gas == nil {
return nil , fmt . Errorf ( "gas not specified" )
}
@ -408,7 +410,7 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs
}
signed , err := s . signTransaction ( ctx , & args , passwd )
if err != nil {
log . Warn ( "Failed transaction sign attempt" , "from" , args . From , "to" , args . To , "value" , args . Value . ToInt ( ) , "err" , err )
log . Warn ( "Failed transaction sign attempt" , "from" , args . from ( ) , "to" , args . To , "value" , args . Value . ToInt ( ) , "err" , err )
return nil , err
}
data , err := signed . MarshalBinary ( )
@ -473,7 +475,7 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt
// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated
// and will be removed in the future. It primary goal is to give clients time to update.
func ( s * PrivateAccountAPI ) SignAndSendTransaction ( ctx context . Context , args SendTx Args, passwd string ) ( common . Hash , error ) {
func ( s * PrivateAccountAPI ) SignAndSendTransaction ( ctx context . Context , args Transaction Args, passwd string ) ( common . Hash , error ) {
return s . SendTransaction ( ctx , args , passwd )
}
@ -566,6 +568,7 @@ type AccountResult struct {
StorageHash common . Hash ` json:"storageHash" `
StorageProof [ ] StorageResult ` json:"storageProof" `
}
type StorageResult struct {
Key string ` json:"key" `
Value * hexutil . Big ` json:"value" `
@ -751,58 +754,6 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A
return res [ : ] , state . Error ( )
}
// CallArgs represents the arguments for a call.
type CallArgs struct {
From * common . Address ` json:"from" `
To * common . Address ` json:"to" `
Gas * hexutil . Uint64 ` json:"gas" `
GasPrice * hexutil . Big ` json:"gasPrice" `
Value * hexutil . Big ` json:"value" `
Data * hexutil . Bytes ` json:"data" `
AccessList * types . AccessList ` json:"accessList" `
}
// ToMessage converts CallArgs to the Message type used by the core evm
func ( args * CallArgs ) ToMessage ( globalGasCap uint64 ) types . Message {
// Set sender address or use zero address if none specified.
var addr common . Address
if args . From != nil {
addr = * args . From
}
// Set default gas & gas price if none were set
gas := globalGasCap
if gas == 0 {
gas = uint64 ( math . MaxUint64 / 2 )
}
if args . Gas != nil {
gas = uint64 ( * args . Gas )
}
if globalGasCap != 0 && globalGasCap < gas {
log . Warn ( "Caller gas above allowance, capping" , "requested" , gas , "cap" , globalGasCap )
gas = globalGasCap
}
gasPrice := new ( big . Int )
if args . GasPrice != nil {
gasPrice = args . GasPrice . ToInt ( )
}
value := new ( big . Int )
if args . Value != nil {
value = args . Value . ToInt ( )
}
var data [ ] byte
if args . Data != nil {
data = * args . Data
}
var accessList types . AccessList
if args . AccessList != nil {
accessList = * args . AccessList
}
msg := types . NewMessage ( addr , args . To , 0 , value , gas , gasPrice , nil , nil , data , accessList , false )
return msg
}
// OverrideAccount indicates the overriding fields of account during the execution
// of a message call.
// Note, state and stateDiff can't be specified at the same time. If state is
@ -855,7 +806,7 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
return nil
}
func DoCall ( ctx context . Context , b Backend , args Call Args, blockNrOrHash rpc . BlockNumberOrHash , overrides * StateOverride , vmCfg vm . Config , timeout time . Duration , globalGasCap uint64 ) ( * core . ExecutionResult , error ) {
func DoCall ( ctx context . Context , b Backend , args Transaction Args, blockNrOrHash rpc . BlockNumberOrHash , overrides * StateOverride , vmCfg vm . Config , timeout time . Duration , globalGasCap uint64 ) ( * core . ExecutionResult , error ) {
defer func ( start time . Time ) { log . Debug ( "Executing EVM call finished" , "runtime" , time . Since ( start ) ) } ( time . Now ( ) )
state , header , err := b . StateAndHeaderByNumberOrHash ( ctx , blockNrOrHash )
@ -943,7 +894,7 @@ func (e *revertError) ErrorData() interface{} {
//
// Note, this function doesn't make and changes in the state/blockchain and is
// useful to execute and retrieve values.
func ( s * PublicBlockChainAPI ) Call ( ctx context . Context , args Call Args, blockNrOrHash rpc . BlockNumberOrHash , overrides * StateOverride ) ( hexutil . Bytes , error ) {
func ( s * PublicBlockChainAPI ) Call ( ctx context . Context , args Transaction Args, blockNrOrHash rpc . BlockNumberOrHash , overrides * StateOverride ) ( hexutil . Bytes , error ) {
result , err := DoCall ( ctx , s . b , args , blockNrOrHash , overrides , vm . Config { } , 5 * time . Second , s . b . RPCGasCap ( ) )
if err != nil {
return nil , err
@ -955,7 +906,7 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNrOr
return result . Return ( ) , result . Err
}
func DoEstimateGas ( ctx context . Context , b Backend , args Call Args, blockNrOrHash rpc . BlockNumberOrHash , gasCap uint64 ) ( hexutil . Uint64 , error ) {
func DoEstimateGas ( ctx context . Context , b Backend , args Transaction Args, blockNrOrHash rpc . BlockNumberOrHash , gasCap uint64 ) ( hexutil . Uint64 , error ) {
// Binary search the gas requirement, as it may be higher than the amount used
var (
lo uint64 = params . TxGas - 1
@ -1066,7 +1017,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash
// EstimateGas returns an estimate of the amount of gas needed to execute the
// given transaction against the current pending block.
func ( s * PublicBlockChainAPI ) EstimateGas ( ctx context . Context , args Call Args, blockNrOrHash * rpc . BlockNumberOrHash ) ( hexutil . Uint64 , error ) {
func ( s * PublicBlockChainAPI ) EstimateGas ( ctx context . Context , args Transaction Args, blockNrOrHash * rpc . BlockNumberOrHash ) ( hexutil . Uint64 , error ) {
bNrOrHash := rpc . BlockNumberOrHashWithNumber ( rpc . PendingBlockNumber )
if blockNrOrHash != nil {
bNrOrHash = * blockNrOrHash
@ -1324,7 +1275,7 @@ type accessListResult struct {
// CreateAccessList creates a EIP-2930 type AccessList for the given transaction.
// Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state.
func ( s * PublicBlockChainAPI ) CreateAccessList ( ctx context . Context , args SendTx Args, blockNrOrHash * rpc . BlockNumberOrHash ) ( * accessListResult , error ) {
func ( s * PublicBlockChainAPI ) CreateAccessList ( ctx context . Context , args Transaction Args, blockNrOrHash * rpc . BlockNumberOrHash ) ( * accessListResult , error ) {
bNrOrHash := rpc . BlockNumberOrHashWithNumber ( rpc . PendingBlockNumber )
if blockNrOrHash != nil {
bNrOrHash = * blockNrOrHash
@ -1343,7 +1294,7 @@ func (s *PublicBlockChainAPI) CreateAccessList(ctx context.Context, args SendTxA
// AccessList creates an access list for the given transaction.
// If the accesslist creation fails an error is returned.
// If the transaction itself fails, an vmErr is returned.
func AccessList ( ctx context . Context , b Backend , blockNrOrHash rpc . BlockNumberOrHash , args SendTx Args) ( acl types . AccessList , gasUsed uint64 , vmErr error , err error ) {
func AccessList ( ctx context . Context , b Backend , blockNrOrHash rpc . BlockNumberOrHash , args Transaction Args) ( acl types . AccessList , gasUsed uint64 , vmErr error , err error ) {
// Retrieve the execution context
db , header , err := b . StateAndHeaderByNumberOrHash ( ctx , blockNrOrHash )
if db == nil || err != nil {
@ -1361,21 +1312,15 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
if args . To != nil {
to = * args . To
} else {
to = crypto . CreateAddress ( args . From , uint64 ( * args . Nonce ) )
}
var input [ ] byte
if args . Input != nil {
input = * args . Input
} else if args . Data != nil {
input = * args . Data
to = crypto . CreateAddress ( args . from ( ) , uint64 ( * args . Nonce ) )
}
// Retrieve the precompiles since they don't need to be added to the access list
precompiles := vm . ActivePrecompiles ( b . ChainConfig ( ) . Rules ( header . Number ) )
// Create an initial tracer
prevTracer := vm . NewAccessListTracer ( nil , args . From , to , precompiles )
prevTracer := vm . NewAccessListTracer ( nil , args . from ( ) , to , precompiles )
if args . AccessList != nil {
prevTracer = vm . NewAccessListTracer ( * args . AccessList , args . From , to , precompiles )
prevTracer = vm . NewAccessListTracer ( * args . AccessList , args . from ( ) , to , precompiles )
}
for {
// Retrieve the current access list to expand
@ -1393,10 +1338,10 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
}
// Copy the original db so we don't modify it
statedb := db . Copy ( )
msg := types . NewMessage ( args . From , args . To , uint64 ( * args . Nonce ) , args . Value . ToInt ( ) , uint64 ( * args . Gas ) , args . GasPrice . ToInt ( ) , nil , nil , input , accessList , false )
msg := types . NewMessage ( args . from ( ) , args . To , uint64 ( * args . Nonce ) , args . Value . ToInt ( ) , uint64 ( * args . Gas ) , args . GasPrice . ToInt ( ) , nil , nil , args . data ( ) , accessList , false )
// Apply the transaction with the access list tracer
tracer := vm . NewAccessListTracer ( accessList , args . From , to , precompiles )
tracer := vm . NewAccessListTracer ( accessList , args . from ( ) , to , precompiles )
config := vm . Config { Tracer : tracer , Debug : true }
vmenv , _ , err := b . GetEVM ( ctx , msg , statedb , header , & config )
if err != nil {
@ -1597,123 +1542,6 @@ func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transacti
return wallet . SignTx ( account , tx , s . b . ChainConfig ( ) . ChainID )
}
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
type SendTxArgs struct {
From common . Address ` json:"from" `
To * common . Address ` json:"to" `
Gas * hexutil . Uint64 ` json:"gas" `
GasPrice * hexutil . Big ` json:"gasPrice" `
Value * hexutil . Big ` json:"value" `
Nonce * hexutil . Uint64 ` json:"nonce" `
// We accept "data" and "input" for backwards-compatibility reasons. "input" is the
// newer name and should be preferred by clients.
Data * hexutil . Bytes ` json:"data" `
Input * hexutil . Bytes ` json:"input" `
// For non-legacy transactions
AccessList * types . AccessList ` json:"accessList,omitempty" `
ChainID * hexutil . Big ` json:"chainId,omitempty" `
}
// setDefaults fills in default values for unspecified tx fields.
func ( args * SendTxArgs ) setDefaults ( ctx context . Context , b Backend ) error {
if args . GasPrice == nil {
price , err := b . SuggestPrice ( ctx )
if err != nil {
return err
}
args . GasPrice = ( * hexutil . Big ) ( price )
}
if args . Value == nil {
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 )
}
if args . Data != nil && args . Input != nil && ! bytes . Equal ( * args . Data , * args . Input ) {
return errors . New ( ` both "data" and "input" are set and not equal. Please use "input" to pass transaction call data ` )
}
if args . To == nil {
// Contract creation
var input [ ] byte
if args . Data != nil {
input = * args . Data
} else if args . Input != nil {
input = * args . Input
}
if len ( input ) == 0 {
return errors . New ( ` contract creation without any data provided ` )
}
}
// Estimate the gas usage if necessary.
if args . Gas == nil {
// For backwards-compatibility reason, we try both input and data
// but input is preferred.
input := args . Input
if input == nil {
input = args . Data
}
callArgs := CallArgs {
From : & args . From , // From shouldn't be nil
To : args . To ,
GasPrice : args . GasPrice ,
Value : args . Value ,
Data : input ,
AccessList : args . AccessList ,
}
pendingBlockNr := rpc . BlockNumberOrHashWithNumber ( rpc . PendingBlockNumber )
estimated , err := DoEstimateGas ( ctx , b , callArgs , pendingBlockNr , b . RPCGasCap ( ) )
if err != nil {
return err
}
args . Gas = & estimated
log . Trace ( "Estimate gas usage automatically" , "gas" , args . Gas )
}
if args . ChainID == nil {
id := ( * hexutil . Big ) ( b . ChainConfig ( ) . ChainID )
args . ChainID = id
}
return nil
}
// toTransaction converts the arguments to a transaction.
// This assumes that setDefaults has been called.
func ( args * SendTxArgs ) toTransaction ( ) * types . Transaction {
var input [ ] byte
if args . Input != nil {
input = * args . Input
} else if args . Data != nil {
input = * args . Data
}
var data types . TxData
if args . AccessList == nil {
data = & types . LegacyTx {
To : args . To ,
Nonce : uint64 ( * args . Nonce ) ,
Gas : uint64 ( * args . Gas ) ,
GasPrice : ( * big . Int ) ( args . GasPrice ) ,
Value : ( * big . Int ) ( args . Value ) ,
Data : input ,
}
} else {
data = & types . AccessListTx {
To : args . To ,
ChainID : ( * big . Int ) ( args . ChainID ) ,
Nonce : uint64 ( * args . Nonce ) ,
Gas : uint64 ( * args . Gas ) ,
GasPrice : ( * big . Int ) ( args . GasPrice ) ,
Value : ( * big . Int ) ( args . Value ) ,
Data : input ,
AccessList : * args . AccessList ,
}
}
return types . NewTx ( data )
}
// SubmitTransaction is a helper function that submits tx to txPool and logs a message.
func SubmitTransaction ( ctx context . Context , b Backend , tx * types . Transaction ) ( common . Hash , error ) {
// If the transaction fee cap is already specified, ensure the
@ -1746,9 +1574,9 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c
// 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 SendTx Args) ( common . Hash , error ) {
func ( s * PublicTransactionPoolAPI ) SendTransaction ( ctx context . Context , args Transaction Args) ( common . Hash , error ) {
// Look up the wallet containing the requested signer
account := accounts . Account { Address : args . From }
account := accounts . Account { Address : args . from ( ) }
wallet , err := s . b . AccountManager ( ) . Find ( account )
if err != nil {
@ -1758,8 +1586,8 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
if args . Nonce == nil {
// Hold the addresse's mutex around signing to prevent concurrent assignment of
// the same nonce to multiple accounts.
s . nonceLock . LockAddr ( args . From )
defer s . nonceLock . UnlockAddr ( args . From )
s . nonceLock . LockAddr ( args . from ( ) )
defer s . nonceLock . UnlockAddr ( args . from ( ) )
}
// Set some sanity defaults and terminate on failure
@ -1778,7 +1606,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
// FillTransaction fills the defaults (nonce, gas, gasPrice) on a given unsigned transaction,
// and returns it to the caller for further processing (signing + broadcast)
func ( s * PublicTransactionPoolAPI ) FillTransaction ( ctx context . Context , args SendTx Args) ( * SignTransactionResult , error ) {
func ( s * PublicTransactionPoolAPI ) FillTransaction ( ctx context . Context , args Transaction Args) ( * SignTransactionResult , error ) {
// Set some sanity defaults and terminate on failure
if err := args . setDefaults ( ctx , s . b ) ; err != nil {
return nil , err
@ -1836,7 +1664,7 @@ type SignTransactionResult struct {
// 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 SendTx Args) ( * SignTransactionResult , error ) {
func ( s * PublicTransactionPoolAPI ) SignTransaction ( ctx context . Context , args Transaction Args) ( * SignTransactionResult , error ) {
if args . Gas == nil {
return nil , fmt . Errorf ( "gas not specified" )
}
@ -1853,7 +1681,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen
if err := checkTxFee ( args . GasPrice . ToInt ( ) , uint64 ( * args . Gas ) , s . b . RPCTxFeeCap ( ) ) ; err != nil {
return nil , err
}
tx , err := s . sign ( args . From , args . toTransaction ( ) )
tx , err := s . sign ( args . from ( ) , args . toTransaction ( ) )
if err != nil {
return nil , err
}
@ -1889,7 +1717,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
// 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 SendTx Args, gasPrice * hexutil . Big , gasLimit * hexutil . Uint64 ) ( common . Hash , error ) {
func ( s * PublicTransactionPoolAPI ) Resend ( ctx context . Context , sendArgs Transaction Args, gasPrice * hexutil . Big , gasLimit * hexutil . Uint64 ) ( common . Hash , error ) {
if sendArgs . Nonce == nil {
return common . Hash { } , fmt . Errorf ( "missing transaction nonce in transaction spec" )
}
@ -1918,7 +1746,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
for _ , p := range pending {
wantSigHash := s . signer . Hash ( matchTx )
pFrom , err := types . Sender ( s . signer , p )
if err == nil && pFrom == sendArgs . From && s . signer . Hash ( p ) == wantSigHash {
if err == nil && pFrom == sendArgs . from ( ) && s . signer . Hash ( p ) == wantSigHash {
// Match. Re-sign and send the transaction.
if gasPrice != nil && ( * big . Int ) ( gasPrice ) . Sign ( ) != 0 {
sendArgs . GasPrice = gasPrice
@ -1926,7 +1754,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
if gasLimit != nil && * gasLimit != 0 {
sendArgs . Gas = gasLimit
}
signedTx , err := s . sign ( sendArgs . From , sendArgs . toTransaction ( ) )
signedTx , err := s . sign ( sendArgs . from ( ) , sendArgs . toTransaction ( ) )
if err != nil {
return common . Hash { } , err
}