Refactor call and estimateGas to use ethapi struct type

This commit is contained in:
Nick Johnson 2018-10-16 14:13:21 +01:00
parent 8790e18ae7
commit ba6f531027
4 changed files with 85 additions and 63 deletions

View file

@ -272,6 +272,21 @@ func (b Uint64) String() string {
return EncodeUint64(uint64(b))
}
func (b Uint64) ImplementsGraphQLType(name string) bool { return name == "Long" }
func (b *Uint64) UnmarshalGraphQL(input interface{}) error {
var err error
switch input := input.(type) {
case string:
return b.UnmarshalText([]byte(input))
case int32:
*b = Uint64(input)
default:
err = fmt.Errorf("Unexpected type for BigInt: %v", input)
}
return err
}
// Uint marshals/unmarshals as a JSON string with 0x prefix.
// The zero value marshals as "0x0".
type Uint uint

View file

@ -268,6 +268,19 @@ func (a Address) Value() (driver.Value, error) {
return a[:], nil
}
func (a Address) ImplementsGraphQLType(name string) bool { return name == "Address" }
func (a *Address) UnmarshalGraphQL(input interface{}) error {
var err error
switch input := input.(type) {
case string:
*a = HexToAddress(input)
default:
err = fmt.Errorf("Unexpected type for Hash: %v", input)
}
return err
}
// UnprefixedAddress allows marshaling an Address without 0x prefix.
type UnprefixedAddress Address

View file

@ -848,13 +848,12 @@ func (r *Resolver) SendRawTransaction(ctx context.Context, args struct{ Data hex
}
type CallData struct {
From *Address
To *Address
Gas *int32
GasPrice *hexutil.Big
Value *hexutil.Big
Data *hexutil.Bytes
BlockNumber *int32
From *Address
To *Address
Gas *hexutil.Uint64
GasPrice *hexutil.Big
Value *hexutil.Big
Data *hexutil.Bytes
}
type CallResult struct {
@ -875,45 +874,21 @@ func (c *CallResult) Status() int32 {
return c.status
}
func convertCallData(data CallData) (ethapi.CallArgs, rpc.BlockNumber) {
callArgs := ethapi.CallArgs{}
if data.From != nil {
callArgs.From = data.From.Address
}
if data.To != nil {
addr := data.To.Address
callArgs.To = &addr
}
if data.Gas != nil {
callArgs.Gas = hexutil.Uint64(*data.Gas)
}
if data.GasPrice != nil {
callArgs.GasPrice = *data.GasPrice
}
if data.Value != nil {
callArgs.Value = *data.Value
}
if data.Data != nil {
callArgs.Data = *data.Data
}
blockNumber := rpc.LatestBlockNumber
if data.BlockNumber != nil {
blockNumber = rpc.BlockNumber(*data.BlockNumber)
}
return callArgs, blockNumber
}
func (r *Resolver) Call(ctx context.Context, args struct{ Data CallData }) (*CallResult, error) {
func (r *Resolver) Call(ctx context.Context, args struct {
Data ethapi.CallArgs
BlockNumber *int32
}) (*CallResult, error) {
be, err := getBackend(r.node)
if err != nil {
return nil, err
}
callArgs, blockNumber := convertCallData(args.Data)
blockNumber := rpc.LatestBlockNumber
if args.BlockNumber != nil {
blockNumber = rpc.BlockNumber(*args.BlockNumber)
}
result, gas, failed, err := ethapi.DoCall(ctx, be, callArgs, blockNumber, vm.Config{}, 5*time.Second)
result, gas, failed, err := ethapi.DoCall(ctx, be, args.Data, blockNumber, vm.Config{}, 5*time.Second)
status := int32(1)
if failed {
status = 0
@ -925,15 +900,21 @@ func (r *Resolver) Call(ctx context.Context, args struct{ Data CallData }) (*Cal
}, err
}
func (r *Resolver) EstimateGas(ctx context.Context, args struct{ Data CallData }) (int32, error) {
func (r *Resolver) EstimateGas(ctx context.Context, args struct {
Data ethapi.CallArgs
BlockNumber *int32
}) (int32, error) {
be, err := getBackend(r.node)
if err != nil {
return 0, err
}
callArgs, blockNumber := convertCallData(args.Data)
blockNumber := rpc.LatestBlockNumber
if args.BlockNumber != nil {
blockNumber = rpc.BlockNumber(*args.BlockNumber)
}
gas, err := ethapi.DoEstimateGas(ctx, be, callArgs, blockNumber)
gas, err := ethapi.DoEstimateGas(ctx, be, args.Data, blockNumber)
return int32(gas), err
}
@ -945,6 +926,7 @@ func NewHandler(n *node.Node) (http.Handler, error) {
scalar Address
scalar Bytes
scalar BigInt
scalar Long
schema {
query: Query
@ -1015,11 +997,10 @@ func NewHandler(n *node.Node) (http.Handler, error) {
input CallData {
from: Address
to: Address
gas: Int
gas: Long
gasPrice: BigInt
value: BigInt
data: Bytes
blockNumber: Int
}
type CallResult {
@ -1033,8 +1014,8 @@ func NewHandler(n *node.Node) (http.Handler, error) {
block(number: Int, hash: Bytes32): Block
blocks(from: Int!, to: Int): [Block!]!
transaction(hash: Bytes32!): Transaction
call(data: CallData!): CallResult
estimateGas(data: CallData!): Int!
call(data: CallData!, blockNumber: Int): CallResult
estimateGas(data: CallData!, blockNumber: Int): Int!
}
type Mutation {

View file

@ -609,12 +609,12 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A
// CallArgs represents the arguments for a call.
type CallArgs struct {
From common.Address `json:"from"`
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"`
Gas *hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
Value *hexutil.Big `json:"value"`
Data *hexutil.Bytes `json:"data"`
}
func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration) ([]byte, uint64, bool, error) {
@ -625,25 +625,38 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
return nil, 0, false, err
}
// Set sender address or use a default if none specified
addr := args.From
if addr == (common.Address{}) {
var addr common.Address
if args.From == nil {
if wallets := b.AccountManager().Wallets(); len(wallets) > 0 {
if accounts := wallets[0].Accounts(); len(accounts) > 0 {
addr = accounts[0].Address
}
}
} else {
addr = *args.From
}
// Set default gas & gas price if none were set
gas, gasPrice := uint64(args.Gas), args.GasPrice.ToInt()
if gas == 0 {
gas = math.MaxUint64 / 2
gas := uint64(math.MaxUint64 / 2)
if args.Gas != nil {
gas = uint64(*args.Gas)
}
if gasPrice.Sign() == 0 {
gasPrice = new(big.Int).SetUint64(defaultGasPrice)
gasPrice := new(big.Int).SetUint64(defaultGasPrice)
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 = []byte(*args.Data)
}
// Create new call message
msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false)
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false)
// Setup context so it may be cancelled the call has completed
// or, in case of unmetered gas, setup a context with a timeout.
@ -695,8 +708,8 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
hi uint64
cap uint64
)
if uint64(args.Gas) >= params.TxGas {
hi = uint64(args.Gas)
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
hi = uint64(*args.Gas)
} else {
// Retrieve the block to act as the gas ceiling
block, err := b.BlockByNumber(ctx, blockNr)
@ -709,7 +722,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) bool {
args.Gas = hexutil.Uint64(gas)
args.Gas = (*hexutil.Uint64)(&gas)
_, _, failed, err := DoCall(ctx, b, args, blockNr, vm.Config{}, 0)
if err != nil || failed {