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)) 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. // Uint marshals/unmarshals as a JSON string with 0x prefix.
// The zero value marshals as "0x0". // The zero value marshals as "0x0".
type Uint uint type Uint uint

View file

@ -268,6 +268,19 @@ func (a Address) Value() (driver.Value, error) {
return a[:], nil 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. // UnprefixedAddress allows marshaling an Address without 0x prefix.
type UnprefixedAddress Address type UnprefixedAddress Address

View file

@ -848,13 +848,12 @@ func (r *Resolver) SendRawTransaction(ctx context.Context, args struct{ Data hex
} }
type CallData struct { type CallData struct {
From *Address From *Address
To *Address To *Address
Gas *int32 Gas *hexutil.Uint64
GasPrice *hexutil.Big GasPrice *hexutil.Big
Value *hexutil.Big Value *hexutil.Big
Data *hexutil.Bytes Data *hexutil.Bytes
BlockNumber *int32
} }
type CallResult struct { type CallResult struct {
@ -875,45 +874,21 @@ func (c *CallResult) Status() int32 {
return c.status return c.status
} }
func convertCallData(data CallData) (ethapi.CallArgs, rpc.BlockNumber) { func (r *Resolver) Call(ctx context.Context, args struct {
callArgs := ethapi.CallArgs{} Data ethapi.CallArgs
if data.From != nil { BlockNumber *int32
callArgs.From = data.From.Address }) (*CallResult, error) {
}
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) {
be, err := getBackend(r.node) be, err := getBackend(r.node)
if err != nil { if err != nil {
return nil, err 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) status := int32(1)
if failed { if failed {
status = 0 status = 0
@ -925,15 +900,21 @@ func (r *Resolver) Call(ctx context.Context, args struct{ Data CallData }) (*Cal
}, err }, 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) be, err := getBackend(r.node)
if err != nil { if err != nil {
return 0, err 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 return int32(gas), err
} }
@ -945,6 +926,7 @@ func NewHandler(n *node.Node) (http.Handler, error) {
scalar Address scalar Address
scalar Bytes scalar Bytes
scalar BigInt scalar BigInt
scalar Long
schema { schema {
query: Query query: Query
@ -1015,11 +997,10 @@ func NewHandler(n *node.Node) (http.Handler, error) {
input CallData { input CallData {
from: Address from: Address
to: Address to: Address
gas: Int gas: Long
gasPrice: BigInt gasPrice: BigInt
value: BigInt value: BigInt
data: Bytes data: Bytes
blockNumber: Int
} }
type CallResult { type CallResult {
@ -1033,8 +1014,8 @@ func NewHandler(n *node.Node) (http.Handler, error) {
block(number: Int, hash: Bytes32): Block block(number: Int, hash: Bytes32): Block
blocks(from: Int!, to: Int): [Block!]! blocks(from: Int!, to: Int): [Block!]!
transaction(hash: Bytes32!): Transaction transaction(hash: Bytes32!): Transaction
call(data: CallData!): CallResult call(data: CallData!, blockNumber: Int): CallResult
estimateGas(data: CallData!): Int! estimateGas(data: CallData!, blockNumber: Int): Int!
} }
type Mutation { 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. // CallArgs represents the arguments for a call.
type CallArgs struct { type CallArgs struct {
From common.Address `json:"from"` From *common.Address `json:"from"`
To *common.Address `json:"to"` To *common.Address `json:"to"`
Gas hexutil.Uint64 `json:"gas"` Gas *hexutil.Uint64 `json:"gas"`
GasPrice hexutil.Big `json:"gasPrice"` GasPrice *hexutil.Big `json:"gasPrice"`
Value hexutil.Big `json:"value"` Value *hexutil.Big `json:"value"`
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) ([]byte, uint64, bool, error) { 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 return nil, 0, false, err
} }
// Set sender address or use a default if none specified // Set sender address or use a default if none specified
addr := args.From var addr common.Address
if addr == (common.Address{}) { if args.From == nil {
if wallets := b.AccountManager().Wallets(); len(wallets) > 0 { if wallets := b.AccountManager().Wallets(); len(wallets) > 0 {
if accounts := wallets[0].Accounts(); len(accounts) > 0 { if accounts := wallets[0].Accounts(); len(accounts) > 0 {
addr = accounts[0].Address addr = accounts[0].Address
} }
} }
} else {
addr = *args.From
} }
// Set default gas & gas price if none were set // Set default gas & gas price if none were set
gas, gasPrice := uint64(args.Gas), args.GasPrice.ToInt() gas := uint64(math.MaxUint64 / 2)
if gas == 0 { if args.Gas != nil {
gas = math.MaxUint64 / 2 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 // 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 // Setup context so it may be cancelled the call has completed
// or, in case of unmetered gas, setup a context with a timeout. // 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 hi uint64
cap uint64 cap uint64
) )
if uint64(args.Gas) >= params.TxGas { if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
hi = uint64(args.Gas) hi = uint64(*args.Gas)
} else { } else {
// Retrieve the block to act as the gas ceiling // Retrieve the block to act as the gas ceiling
block, err := b.BlockByNumber(ctx, blockNr) 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 // Create a helper to check if a gas allowance results in an executable transaction
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, blockNr, vm.Config{}, 0) _, _, failed, err := DoCall(ctx, b, args, blockNr, vm.Config{}, 0)
if err != nil || failed { if err != nil || failed {