Skip to content

Commit

Permalink
update param to BlockNumberOrHash from BlockNumber for etrue_call
Browse files Browse the repository at this point in the history
  • Loading branch information
iceming123 committed Aug 24, 2021
1 parent 170eb8e commit 05d01e8
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 7 deletions.
22 changes: 21 additions & 1 deletion etrue/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package etrue

import (
"context"
"errors"
"math/big"

"github.com/truechain/truechain-engineering-code/accounts"
Expand Down Expand Up @@ -132,7 +133,15 @@ func (b *TrueAPIBackend) SnailBlockByNumber(ctx context.Context, blockNr rpc.Blo
}
return b.etrue.snailblockchain.GetBlockByNumber(uint64(blockNr)), nil
}

func (b *TrueAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
if blockNr, ok := blockNrOrHash.Number(); ok {
return b.StateAndHeaderByNumber(ctx, blockNr)
}
if hash, ok := blockNrOrHash.Hash(); ok {
return b.StateAndHeaderByHash(ctx,hash)
}
return nil, nil, errors.New("invalid arguments; neither block nor hash specified")
}
// StateAndHeaderByNumber returns the state of block by the number
func (b *TrueAPIBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
// Pending state is only known by the miner
Expand All @@ -149,6 +158,17 @@ func (b *TrueAPIBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc
stateDb, err := b.etrue.BlockChain().StateAt(header.Root)
return stateDb, header, err
}
func (b *TrueAPIBackend) StateAndHeaderByHash(ctx context.Context, hash common.Hash) (*state.StateDB, *types.Header, error) {
header, err := b.HeaderByHash(ctx, hash)
if err != nil {
return nil, nil, err
}
if header == nil {
return nil, nil, errors.New("header for hash not found")
}
stateDb, err := b.etrue.BlockChain().StateAt(header.Root)
return stateDb, header, err
}

// GetBlock returns the block by the block's hash
func (b *TrueAPIBackend) GetBlock(ctx context.Context, hash common.Hash) (*types.Block, error) {
Expand Down
12 changes: 6 additions & 6 deletions internal/trueapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -828,10 +828,10 @@ type CallArgs struct {
Fee hexutil.Big `json:"fee"`
}

func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration) (*core.ExecutionResult, error) {
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockHr rpc.BlockNumberOrHash, vmCfg vm.Config, timeout time.Duration) (*core.ExecutionResult, error) {
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())

state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
state, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockHr)
if state == nil || err != nil {
return nil, err
}
Expand Down Expand Up @@ -899,8 +899,8 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr

// 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) {
result, err := s.doCall(ctx, args, blockNr, vm.Config{}, 5*time.Second)
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockHr rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
result, err := s.doCall(ctx, args, blockHr, vm.Config{}, 5*time.Second)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -935,8 +935,8 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
args.Gas = hexutil.Uint64(gas)

result, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}, 0)
blockhr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
result, err := s.doCall(ctx, args, blockhr, vm.Config{}, 0)
if err != nil {
if errors.Is(err, core.ErrIntrinsicGas) {
return true, nil, nil // Special case, raise gas limit
Expand Down
2 changes: 2 additions & 0 deletions internal/trueapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ type Backend interface {
BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error)
SnailBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.SnailBlock, error)
GetFruit(ctx context.Context, fastblockHash common.Hash) (*types.SnailBlock, error)
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error)
StateAndHeaderByHash(ctx context.Context, hash common.Hash) (*state.StateDB, *types.Header, error)
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
GetSnailBlock(ctx context.Context, blockHash common.Hash) (*types.SnailBlock, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
Expand Down
17 changes: 17 additions & 0 deletions les/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package les

import (
"context"
"errors"
"github.com/truechain/truechain-engineering-code/light/fast"
"math/big"

Expand Down Expand Up @@ -99,6 +100,15 @@ func (b *LesApiBackend) SnailBlockByNumber(ctx context.Context, blockNr rpc.Bloc
}
return b.GetSnailBlock(ctx, header.Hash())
}
func (b *LesApiBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
if blockNr, ok := blockNrOrHash.Number(); ok {
return b.StateAndHeaderByNumber(ctx, blockNr)
}
if hash, ok := blockNrOrHash.Hash(); ok {
return b.StateAndHeaderByHash(ctx,hash)
}
return nil, nil, errors.New("invalid arguments; neither block nor hash specified")
}

func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
header, err := b.HeaderByNumber(ctx, blockNr)
Expand All @@ -107,6 +117,13 @@ func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.
}
return fast.NewState(ctx, header, b.etrue.odr), header, nil
}
func (b *LesApiBackend) StateAndHeaderByHash(ctx context.Context, hash common.Hash) (*state.StateDB, *types.Header, error) {
header, err := b.HeaderByHash(ctx, hash)
if header == nil || err != nil {
return nil, nil, err
}
return fast.NewState(ctx, header, b.etrue.odr), header, nil
}

func (b *LesApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) {
return b.etrue.fblockchain.GetBlockByHash(ctx, blockHash)
Expand Down
115 changes: 115 additions & 0 deletions rpc/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
package rpc

import (
"encoding/json"
"fmt"
"github.com/truechain/truechain-engineering-code/common"
"math"
"reflect"
"strconv"
"strings"
"sync"

Expand Down Expand Up @@ -256,3 +259,115 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
func (bn BlockNumber) Int64() int64 {
return (int64)(bn)
}

type BlockNumberOrHash struct {
BlockNumber *BlockNumber `json:"blockNumber,omitempty"`
BlockHash *common.Hash `json:"blockHash,omitempty"`
RequireCanonical bool `json:"requireCanonical,omitempty"`
}

func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error {
type erased BlockNumberOrHash
e := erased{}
err := json.Unmarshal(data, &e)
if err == nil {
if e.BlockNumber != nil && e.BlockHash != nil {
return fmt.Errorf("cannot specify both BlockHash and BlockNumber, choose one or the other")
}
bnh.BlockNumber = e.BlockNumber
bnh.BlockHash = e.BlockHash
bnh.RequireCanonical = e.RequireCanonical
return nil
}
var input string
err = json.Unmarshal(data, &input)
if err != nil {
return err
}
switch input {
case "earliest":
bn := EarliestBlockNumber
bnh.BlockNumber = &bn
return nil
case "latest":
bn := LatestBlockNumber
bnh.BlockNumber = &bn
return nil
case "pending":
bn := PendingBlockNumber
bnh.BlockNumber = &bn
return nil
default:
if len(input) == 66 {
hash := common.Hash{}
err := hash.UnmarshalText([]byte(input))
if err != nil {
return err
}
bnh.BlockHash = &hash
return nil
} else {
blckNum, err := hexutil.DecodeUint64(input)
if err != nil {
return err
}
if blckNum > math.MaxInt64 {
return fmt.Errorf("blocknumber too high")
}
bn := BlockNumber(blckNum)
bnh.BlockNumber = &bn
return nil
}
}
}

func (bnh *BlockNumberOrHash) Number() (BlockNumber, bool) {
if bnh.BlockNumber != nil {
return *bnh.BlockNumber, true
}
return BlockNumber(0), false
}

func (bnh *BlockNumberOrHash) Hash() (common.Hash, bool) {
if bnh.BlockHash != nil {
return *bnh.BlockHash, true
}
return common.Hash{}, false
}

func BlockNumberOrHashWithNumber(blockNr BlockNumber) BlockNumberOrHash {
return BlockNumberOrHash{
BlockNumber: &blockNr,
BlockHash: nil,
RequireCanonical: false,
}
}

func BlockNumberOrHashWithHash(hash common.Hash, canonical bool) BlockNumberOrHash {
return BlockNumberOrHash{
BlockNumber: nil,
BlockHash: &hash,
RequireCanonical: canonical,
}
}

// DecimalOrHex unmarshals a non-negative decimal or hex parameter into a uint64.
type DecimalOrHex uint64

// UnmarshalJSON implements json.Unmarshaler.
func (dh *DecimalOrHex) UnmarshalJSON(data []byte) error {
input := strings.TrimSpace(string(data))
if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
input = input[1 : len(input)-1]
}

value, err := strconv.ParseUint(input, 10, 64)
if err != nil {
value, err = hexutil.DecodeUint64(input)
}
if err != nil {
return err
}
*dh = DecimalOrHex(value)
return nil
}
57 changes: 57 additions & 0 deletions rpc/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,60 @@ func TestBlockNumberJSONUnmarshal(t *testing.T) {
}
}
}

func TestBlockNumberOrHash_UnmarshalJSON(t *testing.T) {
tests := []struct {
input string
mustFail bool
expected BlockNumberOrHash
}{
0: {`"0x"`, true, BlockNumberOrHash{}},
1: {`"0x0"`, false, BlockNumberOrHashWithNumber(0)},
2: {`"0X1"`, false, BlockNumberOrHashWithNumber(1)},
3: {`"0x00"`, true, BlockNumberOrHash{}},
4: {`"0x01"`, true, BlockNumberOrHash{}},
5: {`"0x1"`, false, BlockNumberOrHashWithNumber(1)},
6: {`"0x12"`, false, BlockNumberOrHashWithNumber(18)},
7: {`"0x7fffffffffffffff"`, false, BlockNumberOrHashWithNumber(math.MaxInt64)},
8: {`"0x8000000000000000"`, true, BlockNumberOrHash{}},
9: {"0", true, BlockNumberOrHash{}},
10: {`"ff"`, true, BlockNumberOrHash{}},
11: {`"pending"`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)},
12: {`"latest"`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)},
13: {`"earliest"`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)},
14: {`someString`, true, BlockNumberOrHash{}},
15: {`""`, true, BlockNumberOrHash{}},
16: {``, true, BlockNumberOrHash{}},
17: {`"0x0000000000000000000000000000000000000000000000000000000000000000"`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)},
18: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)},
19: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":false}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)},
20: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":true}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), true)},
21: {`{"blockNumber":"0x1"}`, false, BlockNumberOrHashWithNumber(1)},
22: {`{"blockNumber":"pending"}`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)},
23: {`{"blockNumber":"latest"}`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)},
24: {`{"blockNumber":"earliest"}`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)},
25: {`{"blockNumber":"0x1", "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, true, BlockNumberOrHash{}},
}

for i, test := range tests {
var bnh BlockNumberOrHash
err := json.Unmarshal([]byte(test.input), &bnh)
if test.mustFail && err == nil {
t.Errorf("Test %d should fail", i)
continue
}
if !test.mustFail && err != nil {
t.Errorf("Test %d should pass but got err: %v", i, err)
continue
}
hash, hashOk := bnh.Hash()
expectedHash, expectedHashOk := test.expected.Hash()
num, numOk := bnh.Number()
expectedNum, expectedNumOk := test.expected.Number()
if bnh.RequireCanonical != test.expected.RequireCanonical ||
hash != expectedHash || hashOk != expectedHashOk ||
num != expectedNum || numOk != expectedNumOk {
t.Errorf("Test %d got unexpected value, want %v, got %v", i, test.expected, bnh)
}
}
}

0 comments on commit 05d01e8

Please sign in to comment.