@ -743,7 +743,21 @@ type CallArgs struct {
Data * hexutil . Bytes ` json:"data" `
Data * hexutil . Bytes ` json:"data" `
}
}
func DoCall ( ctx context . Context , b Backend , args CallArgs , blockNr rpc . BlockNumber , vmCfg vm . Config , timeout time . Duration , globalGasCap * big . Int ) ( [ ] byte , uint64 , bool , error ) {
// account 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
// set, message execution will only use the data in the given state. Otherwise
// if statDiff is set, all diff will be applied first and then execute the call
// message.
type account struct {
Nonce * hexutil . Uint64 ` json:"nonce" `
Code * hexutil . Bytes ` json:"code" `
Balance * * hexutil . Big ` json:"balance" `
State * map [ common . Hash ] common . Hash ` json:"state" `
StateDiff * map [ common . Hash ] common . Hash ` json:"stateDiff" `
}
func DoCall ( ctx context . Context , b Backend , args CallArgs , blockNr rpc . BlockNumber , overrides map [ common . Address ] account , vmCfg vm . Config , timeout time . Duration , globalGasCap * big . Int ) ( [ ] byte , uint64 , bool , error ) {
defer func ( start time . Time ) { log . Debug ( "Executing EVM call finished" , "runtime" , time . Since ( start ) ) } ( time . Now ( ) )
defer func ( start time . Time ) { log . Debug ( "Executing EVM call finished" , "runtime" , time . Since ( start ) ) } ( time . Now ( ) )
state , header , err := b . StateAndHeaderByNumber ( ctx , blockNr )
state , header , err := b . StateAndHeaderByNumber ( ctx , blockNr )
@ -761,6 +775,34 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
} else {
} else {
addr = * args . From
addr = * args . From
}
}
// Override the fields of specified contracts before execution.
for addr , account := range overrides {
// Override account nonce.
if account . Nonce != nil {
state . SetNonce ( addr , uint64 ( * account . Nonce ) )
}
// Override account(contract) code.
if account . Code != nil {
state . SetCode ( addr , * account . Code )
}
// Override account balance.
if account . Balance != nil {
state . SetBalance ( addr , ( * big . Int ) ( * account . Balance ) )
}
if account . State != nil && account . StateDiff != nil {
return nil , 0 , false , fmt . Errorf ( "account %s has both 'state' and 'stateDiff'" , addr . Hex ( ) )
}
// Replace entire state if caller requires.
if account . State != nil {
state . SetStorage ( addr , * account . State )
}
// Apply state diff into specified accounts.
if account . StateDiff != nil {
for key , value := range * account . StateDiff {
state . SetState ( addr , key , value )
}
}
}
// Set default gas & gas price if none were set
// Set default gas & gas price if none were set
gas := uint64 ( math . MaxUint64 / 2 )
gas := uint64 ( math . MaxUint64 / 2 )
if args . Gas != nil {
if args . Gas != nil {
@ -827,9 +869,17 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
}
}
// Call executes the given transaction on the state for the given block number.
// Call executes the given transaction on the state for the given block number.
// It 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 CallArgs , blockNr rpc . BlockNumber ) ( hexutil . Bytes , error ) {
// Additionally, the caller can specify a batch of contract for fields overriding.
result , _ , _ , err := DoCall ( ctx , s . b , args , blockNr , vm . Config { } , 5 * time . Second , s . b . RPCGasCap ( ) )
//
// 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 CallArgs , blockNr rpc . BlockNumber , overrides * map [ common . Address ] account ) ( hexutil . Bytes , error ) {
var accounts map [ common . Address ] account
if overrides != nil {
accounts = * overrides
}
result , _ , _ , err := DoCall ( ctx , s . b , args , blockNr , accounts , vm . Config { } , 5 * time . Second , s . b . RPCGasCap ( ) )
return ( hexutil . Bytes ) ( result ) , err
return ( hexutil . Bytes ) ( result ) , err
}
}
@ -860,7 +910,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
executable := func ( gas uint64 ) bool {
executable := func ( gas uint64 ) bool {
args . Gas = ( * hexutil . Uint64 ) ( & gas )
args . Gas = ( * hexutil . Uint64 ) ( & gas )
_ , _ , failed , err := DoCall ( ctx , b , args , rpc . PendingBlockNumber , vm . Config { } , 0 , gasCap )
_ , _ , failed , err := DoCall ( ctx , b , args , rpc . PendingBlockNumber , nil , vm . Config { } , 0 , gasCap )
if err != nil || failed {
if err != nil || failed {
return false
return false
}
}