Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
ad03d980
Commit
ad03d980
authored
Sep 26, 2019
by
Ryan Schneider
Committed by
Felix Lange
Sep 26, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
internal/ethapi: support block number or hash on state-related methods (#19491)
This change adds support for EIP-1898.
parent
62391ddb
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
408 additions
and
166 deletions
+408
-166
blockchain.go
core/blockchain.go
+5
-0
headerchain.go
core/headerchain.go
+4
-0
api_backend.go
eth/api_backend.go
+59
-0
graphql.go
graphql/graphql.go
+102
-146
api.go
internal/ethapi/api.go
+22
-20
backend.go
internal/ethapi/backend.go
+3
-0
api_backend.go
les/api_backend.go
+57
-0
lightchain.go
light/lightchain.go
+5
-0
types.go
rpc/types.go
+93
-0
types_test.go
rpc/types_test.go
+58
-0
No files found.
core/blockchain.go
View file @
ad03d980
...
...
@@ -2139,6 +2139,11 @@ func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool {
return
bc
.
hc
.
HasHeader
(
hash
,
number
)
}
// GetCanonicalHash returns the canonical hash for a given block number
func
(
bc
*
BlockChain
)
GetCanonicalHash
(
number
uint64
)
common
.
Hash
{
return
bc
.
hc
.
GetCanonicalHash
(
number
)
}
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
// hash, fetching towards the genesis block.
func
(
bc
*
BlockChain
)
GetBlockHashesFromHash
(
hash
common
.
Hash
,
max
uint64
)
[]
common
.
Hash
{
...
...
core/headerchain.go
View file @
ad03d980
...
...
@@ -448,6 +448,10 @@ func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
return
hc
.
GetHeader
(
hash
,
number
)
}
func
(
hc
*
HeaderChain
)
GetCanonicalHash
(
number
uint64
)
common
.
Hash
{
return
rawdb
.
ReadCanonicalHash
(
hc
.
chainDb
,
number
)
}
// CurrentHeader retrieves the current head header of the canonical chain. The
// header is retrieved from the HeaderChain's internal cache.
func
(
hc
*
HeaderChain
)
CurrentHeader
()
*
types
.
Header
{
...
...
eth/api_backend.go
View file @
ad03d980
...
...
@@ -72,6 +72,23 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
return
b
.
eth
.
blockchain
.
GetHeaderByNumber
(
uint64
(
number
)),
nil
}
func
(
b
*
EthAPIBackend
)
HeaderByNumberOrHash
(
ctx
context
.
Context
,
blockNrOrHash
rpc
.
BlockNumberOrHash
)
(
*
types
.
Header
,
error
)
{
if
blockNr
,
ok
:=
blockNrOrHash
.
Number
();
ok
{
return
b
.
HeaderByNumber
(
ctx
,
blockNr
)
}
if
hash
,
ok
:=
blockNrOrHash
.
Hash
();
ok
{
header
:=
b
.
eth
.
blockchain
.
GetHeaderByHash
(
hash
)
if
header
==
nil
{
return
nil
,
errors
.
New
(
"header for hash not found"
)
}
if
blockNrOrHash
.
RequireCanonical
&&
b
.
eth
.
blockchain
.
GetCanonicalHash
(
header
.
Number
.
Uint64
())
!=
hash
{
return
nil
,
errors
.
New
(
"hash is not currently canonical"
)
}
return
header
,
nil
}
return
nil
,
errors
.
New
(
"invalid arguments; neither block nor hash specified"
)
}
func
(
b
*
EthAPIBackend
)
HeaderByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
*
types
.
Header
,
error
)
{
return
b
.
eth
.
blockchain
.
GetHeaderByHash
(
hash
),
nil
}
...
...
@@ -93,6 +110,27 @@ func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*typ
return
b
.
eth
.
blockchain
.
GetBlockByHash
(
hash
),
nil
}
func
(
b
*
EthAPIBackend
)
BlockByNumberOrHash
(
ctx
context
.
Context
,
blockNrOrHash
rpc
.
BlockNumberOrHash
)
(
*
types
.
Block
,
error
)
{
if
blockNr
,
ok
:=
blockNrOrHash
.
Number
();
ok
{
return
b
.
BlockByNumber
(
ctx
,
blockNr
)
}
if
hash
,
ok
:=
blockNrOrHash
.
Hash
();
ok
{
header
:=
b
.
eth
.
blockchain
.
GetHeaderByHash
(
hash
)
if
header
==
nil
{
return
nil
,
errors
.
New
(
"header for hash not found"
)
}
if
blockNrOrHash
.
RequireCanonical
&&
b
.
eth
.
blockchain
.
GetCanonicalHash
(
header
.
Number
.
Uint64
())
!=
hash
{
return
nil
,
errors
.
New
(
"hash is not currently canonical"
)
}
block
:=
b
.
eth
.
blockchain
.
GetBlock
(
hash
,
header
.
Number
.
Uint64
())
if
block
==
nil
{
return
nil
,
errors
.
New
(
"header found, but block body is missing"
)
}
return
block
,
nil
}
return
nil
,
errors
.
New
(
"invalid arguments; neither block nor hash specified"
)
}
func
(
b
*
EthAPIBackend
)
StateAndHeaderByNumber
(
ctx
context
.
Context
,
number
rpc
.
BlockNumber
)
(
*
state
.
StateDB
,
*
types
.
Header
,
error
)
{
// Pending state is only known by the miner
if
number
==
rpc
.
PendingBlockNumber
{
...
...
@@ -111,6 +149,27 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
return
stateDb
,
header
,
err
}
func
(
b
*
EthAPIBackend
)
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
{
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"
)
}
if
blockNrOrHash
.
RequireCanonical
&&
b
.
eth
.
blockchain
.
GetCanonicalHash
(
header
.
Number
.
Uint64
())
!=
hash
{
return
nil
,
nil
,
errors
.
New
(
"hash is not currently canonical"
)
}
stateDb
,
err
:=
b
.
eth
.
BlockChain
()
.
StateAt
(
header
.
Root
)
return
stateDb
,
header
,
err
}
return
nil
,
nil
,
errors
.
New
(
"invalid arguments; neither block nor hash specified"
)
}
func
(
b
*
EthAPIBackend
)
GetReceipts
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
types
.
Receipts
,
error
)
{
return
b
.
eth
.
blockchain
.
GetReceiptsByHash
(
hash
),
nil
}
...
...
graphql/graphql.go
View file @
ad03d980
...
...
@@ -36,7 +36,6 @@ import (
)
var
(
errOnlyOnMainChain
=
errors
.
New
(
"this operation is only available for blocks on the canonical chain"
)
errBlockInvariant
=
errors
.
New
(
"block objects must be instantiated with at least one of num or hash"
)
)
...
...
@@ -44,12 +43,12 @@ var (
type
Account
struct
{
backend
ethapi
.
Backend
address
common
.
Address
blockN
umber
rpc
.
BlockNumber
blockN
rOrHash
rpc
.
BlockNumberOrHash
}
// getState fetches the StateDB object for an account.
func
(
a
*
Account
)
getState
(
ctx
context
.
Context
)
(
*
state
.
StateDB
,
error
)
{
state
,
_
,
err
:=
a
.
backend
.
StateAndHeaderByNumber
(
ctx
,
a
.
blockNumber
)
state
,
_
,
err
:=
a
.
backend
.
StateAndHeaderByNumber
OrHash
(
ctx
,
a
.
blockNrOrHash
)
return
state
,
err
}
...
...
@@ -104,7 +103,7 @@ func (l *Log) Account(ctx context.Context, args BlockNumberArgs) *Account {
return
&
Account
{
backend
:
l
.
backend
,
address
:
l
.
log
.
Address
,
blockN
umber
:
args
.
Number
(),
blockN
rOrHash
:
args
.
NumberOrLatest
(),
}
}
...
...
@@ -136,10 +135,10 @@ func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, error) {
tx
,
blockHash
,
_
,
index
:=
rawdb
.
ReadTransaction
(
t
.
backend
.
ChainDb
(),
t
.
hash
)
if
tx
!=
nil
{
t
.
tx
=
tx
blockNrOrHash
:=
rpc
.
BlockNumberOrHashWithHash
(
blockHash
,
false
)
t
.
block
=
&
Block
{
backend
:
t
.
backend
,
hash
:
blockHash
,
canonical
:
unknown
,
numberOrHash
:
&
blockNrOrHash
,
}
t
.
index
=
index
}
else
{
...
...
@@ -205,7 +204,7 @@ func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, e
return
&
Account
{
backend
:
t
.
backend
,
address
:
*
to
,
blockN
umber
:
args
.
Number
(),
blockN
rOrHash
:
args
.
NumberOrLatest
(),
},
nil
}
...
...
@@ -223,7 +222,7 @@ func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account,
return
&
Account
{
backend
:
t
.
backend
,
address
:
from
,
blockN
umber
:
args
.
Number
(),
blockN
rOrHash
:
args
.
NumberOrLatest
(),
},
nil
}
...
...
@@ -295,7 +294,7 @@ func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs)
return
&
Account
{
backend
:
t
.
backend
,
address
:
receipt
.
ContractAddress
,
blockN
umber
:
args
.
Number
(),
blockN
rOrHash
:
args
.
NumberOrLatest
(),
},
nil
}
...
...
@@ -317,45 +316,16 @@ func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) {
type
BlockType
int
const
(
unknown
BlockType
=
iota
isCanonical
notCanonical
)
// Block represents an Ethereum block.
// backend, and
either num or h
ash are mandatory. All other fields are lazily fetched
// backend, and
numberOrH
ash are mandatory. All other fields are lazily fetched
// when required.
type
Block
struct
{
backend
ethapi
.
Backend
num
*
rpc
.
BlockNumber
num
berOrHash
*
rpc
.
BlockNumberOrHash
hash
common
.
Hash
header
*
types
.
Header
block
*
types
.
Block
receipts
[]
*
types
.
Receipt
canonical
BlockType
// Indicates if this block is on the main chain or not.
}
func
(
b
*
Block
)
onMainChain
(
ctx
context
.
Context
)
error
{
if
b
.
canonical
==
unknown
{
header
,
err
:=
b
.
resolveHeader
(
ctx
)
if
err
!=
nil
{
return
err
}
canonHeader
,
err
:=
b
.
backend
.
HeaderByNumber
(
ctx
,
rpc
.
BlockNumber
(
header
.
Number
.
Uint64
()))
if
err
!=
nil
{
return
err
}
if
header
.
Hash
()
==
canonHeader
.
Hash
()
{
b
.
canonical
=
isCanonical
}
else
{
b
.
canonical
=
notCanonical
}
}
if
b
.
canonical
!=
isCanonical
{
return
errOnlyOnMainChain
}
return
nil
}
// resolve returns the internal Block object representing this block, fetching
...
...
@@ -364,14 +334,17 @@ func (b *Block) resolve(ctx context.Context) (*types.Block, error) {
if
b
.
block
!=
nil
{
return
b
.
block
,
nil
}
var
err
error
if
b
.
hash
!=
(
common
.
Hash
{})
{
b
.
block
,
err
=
b
.
backend
.
BlockByHash
(
ctx
,
b
.
hash
)
}
else
{
b
.
block
,
err
=
b
.
backend
.
BlockByNumber
(
ctx
,
*
b
.
num
)
if
b
.
numberOrHash
==
nil
{
latest
:=
rpc
.
BlockNumberOrHashWithNumber
(
rpc
.
LatestBlockNumber
)
b
.
numberOrHash
=
&
latest
}
var
err
error
b
.
block
,
err
=
b
.
backend
.
BlockByNumberOrHash
(
ctx
,
*
b
.
numberOrHash
)
if
b
.
block
!=
nil
&&
b
.
header
==
nil
{
b
.
header
=
b
.
block
.
Header
()
if
hash
,
ok
:=
b
.
numberOrHash
.
Hash
();
ok
{
b
.
hash
=
hash
}
}
return
b
.
block
,
err
}
...
...
@@ -380,7 +353,7 @@ func (b *Block) resolve(ctx context.Context) (*types.Block, error) {
// if necessary. Call this function instead of `resolve` unless you need the
// additional data (transactions and uncles).
func
(
b
*
Block
)
resolveHeader
(
ctx
context
.
Context
)
(
*
types
.
Header
,
error
)
{
if
b
.
num
==
nil
&&
b
.
hash
==
(
common
.
Hash
{})
{
if
b
.
num
berOrHash
==
nil
&&
b
.
hash
==
(
common
.
Hash
{})
{
return
nil
,
errBlockInvariant
}
var
err
error
...
...
@@ -388,7 +361,7 @@ func (b *Block) resolveHeader(ctx context.Context) (*types.Header, error) {
if
b
.
hash
!=
(
common
.
Hash
{})
{
b
.
header
,
err
=
b
.
backend
.
HeaderByHash
(
ctx
,
b
.
hash
)
}
else
{
b
.
header
,
err
=
b
.
backend
.
HeaderByNumber
(
ctx
,
*
b
.
num
)
b
.
header
,
err
=
b
.
backend
.
HeaderByNumber
OrHash
(
ctx
,
*
b
.
numberOrHash
)
}
}
return
b
.
header
,
err
...
...
@@ -416,15 +389,12 @@ func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) {
}
func
(
b
*
Block
)
Number
(
ctx
context
.
Context
)
(
hexutil
.
Uint64
,
error
)
{
if
b
.
num
==
nil
||
*
b
.
num
==
rpc
.
LatestBlockNumber
{
header
,
err
:=
b
.
resolveHeader
(
ctx
)
if
err
!=
nil
{
return
0
,
err
}
num
:=
rpc
.
BlockNumber
(
header
.
Number
.
Uint64
())
b
.
num
=
&
num
}
return
hexutil
.
Uint64
(
*
b
.
num
),
nil
return
hexutil
.
Uint64
(
header
.
Number
.
Uint64
()),
nil
}
func
(
b
*
Block
)
Hash
(
ctx
context
.
Context
)
(
common
.
Hash
,
error
)
{
...
...
@@ -456,26 +426,17 @@ func (b *Block) GasUsed(ctx context.Context) (hexutil.Uint64, error) {
func
(
b
*
Block
)
Parent
(
ctx
context
.
Context
)
(
*
Block
,
error
)
{
// If the block header hasn't been fetched, and we'll need it, fetch it.
if
b
.
num
==
nil
&&
b
.
hash
!=
(
common
.
Hash
{})
&&
b
.
header
==
nil
{
if
b
.
num
berOrHash
==
nil
&&
b
.
header
==
nil
{
if
_
,
err
:=
b
.
resolveHeader
(
ctx
);
err
!=
nil
{
return
nil
,
err
}
}
if
b
.
header
!=
nil
&&
b
.
header
.
Number
.
Uint64
()
>
0
{
num
:=
rpc
.
BlockNumber
(
b
.
header
.
Number
.
Uint64
()
-
1
)
num
:=
rpc
.
BlockNumber
OrHashWithNumber
(
rpc
.
BlockNumber
(
b
.
header
.
Number
.
Uint64
()
-
1
)
)
return
&
Block
{
backend
:
b
.
backend
,
num
:
&
num
,
num
berOrHash
:
&
num
,
hash
:
b
.
header
.
ParentHash
,
canonical
:
unknown
,
},
nil
}
if
b
.
num
!=
nil
&&
*
b
.
num
!=
0
{
num
:=
*
b
.
num
-
1
return
&
Block
{
backend
:
b
.
backend
,
num
:
&
num
,
canonical
:
isCanonical
,
},
nil
}
return
nil
,
nil
...
...
@@ -561,13 +522,11 @@ func (b *Block) Ommers(ctx context.Context) (*[]*Block, error) {
}
ret
:=
make
([]
*
Block
,
0
,
len
(
block
.
Uncles
()))
for
_
,
uncle
:=
range
block
.
Uncles
()
{
blockNumber
:=
rpc
.
BlockNumber
(
uncle
.
Number
.
Uint64
()
)
blockNumber
OrHash
:=
rpc
.
BlockNumberOrHashWithHash
(
uncle
.
Hash
(),
false
)
ret
=
append
(
ret
,
&
Block
{
backend
:
b
.
backend
,
num
:
&
blockNumber
,
hash
:
uncle
.
Hash
(),
numberOrHash
:
&
blockNumberOrHash
,
header
:
uncle
,
canonical
:
notCanonical
,
})
}
return
&
ret
,
nil
...
...
@@ -603,16 +562,26 @@ func (b *Block) TotalDifficulty(ctx context.Context) (hexutil.Big, error) {
// BlockNumberArgs encapsulates arguments to accessors that specify a block number.
type
BlockNumberArgs
struct
{
// TODO: Ideally we could use input unions to allow the query to specify the
// block parameter by hash, block number, or tag but input unions aren't part of the
// standard GraphQL schema SDL yet, see: https://github.com/graphql/graphql-spec/issues/488
Block
*
hexutil
.
Uint64
}
// Number
returns the provided block number, or rpc.LatestBlockNumber
if none
// Number
Or returns the provided block number argument, or the "current" block number or hash
if none
// was provided.
func
(
a
BlockNumberArgs
)
Number
()
rpc
.
BlockNumber
{
func
(
a
BlockNumberArgs
)
Number
Or
(
current
rpc
.
BlockNumberOrHash
)
rpc
.
BlockNumberOrHash
{
if
a
.
Block
!=
nil
{
return
rpc
.
BlockNumber
(
*
a
.
Block
)
blockNr
:=
rpc
.
BlockNumber
(
*
a
.
Block
)
return
rpc
.
BlockNumberOrHashWithNumber
(
blockNr
)
}
return
rpc
.
LatestBlockNumber
return
current
}
// NumberOrLatest returns the provided block number argument, or the "latest" block number if none
// was provided.
func
(
a
BlockNumberArgs
)
NumberOrLatest
()
rpc
.
BlockNumberOrHash
{
return
a
.
NumberOr
(
rpc
.
BlockNumberOrHashWithNumber
(
rpc
.
LatestBlockNumber
))
}
func
(
b
*
Block
)
Miner
(
ctx
context
.
Context
,
args
BlockNumberArgs
)
(
*
Account
,
error
)
{
...
...
@@ -623,7 +592,7 @@ func (b *Block) Miner(ctx context.Context, args BlockNumberArgs) (*Account, erro
return
&
Account
{
backend
:
b
.
backend
,
address
:
header
.
Coinbase
,
blockN
umber
:
args
.
Number
(),
blockN
rOrHash
:
args
.
NumberOrLatest
(),
},
nil
}
...
...
@@ -683,13 +652,11 @@ func (b *Block) OmmerAt(ctx context.Context, args struct{ Index int32 }) (*Block
return
nil
,
nil
}
uncle
:=
uncles
[
args
.
Index
]
blockNumber
:=
rpc
.
BlockNumber
(
uncle
.
Number
.
Uint64
()
)
blockNumber
OrHash
:=
rpc
.
BlockNumberOrHashWithHash
(
uncle
.
Hash
(),
false
)
return
&
Block
{
backend
:
b
.
backend
,
num
:
&
blockNumber
,
hash
:
uncle
.
Hash
(),
numberOrHash
:
&
blockNumberOrHash
,
header
:
uncle
,
canonical
:
notCanonical
,
},
nil
}
...
...
@@ -757,11 +724,7 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri
func
(
b
*
Block
)
Account
(
ctx
context
.
Context
,
args
struct
{
Address
common
.
Address
})
(
*
Account
,
error
)
{
err
:=
b
.
onMainChain
(
ctx
)
if
err
!=
nil
{
return
nil
,
err
}
if
b
.
num
==
nil
{
if
b
.
numberOrHash
==
nil
{
_
,
err
:=
b
.
resolveHeader
(
ctx
)
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -770,7 +733,7 @@ func (b *Block) Account(ctx context.Context, args struct {
return
&
Account
{
backend
:
b
.
backend
,
address
:
args
.
Address
,
blockN
umber
:
*
b
.
num
,
blockN
rOrHash
:
*
b
.
numberOrHash
,
},
nil
}
...
...
@@ -807,17 +770,13 @@ func (c *CallResult) Status() hexutil.Uint64 {
func
(
b
*
Block
)
Call
(
ctx
context
.
Context
,
args
struct
{
Data
ethapi
.
CallArgs
})
(
*
CallResult
,
error
)
{
err
:=
b
.
onMainChain
(
ctx
)
if
b
.
numberOrHash
==
nil
{
_
,
err
:=
b
.
resolve
(
ctx
)
if
err
!=
nil
{
return
nil
,
err
}
if
b
.
num
==
nil
{
_
,
err
:=
b
.
resolveHeader
(
ctx
)
if
err
!=
nil
{
return
nil
,
err
}
}
result
,
gas
,
failed
,
err
:=
ethapi
.
DoCall
(
ctx
,
b
.
backend
,
args
.
Data
,
*
b
.
num
,
nil
,
vm
.
Config
{},
5
*
time
.
Second
,
b
.
backend
.
RPCGasCap
())
result
,
gas
,
failed
,
err
:=
ethapi
.
DoCall
(
ctx
,
b
.
backend
,
args
.
Data
,
*
b
.
numberOrHash
,
nil
,
vm
.
Config
{},
5
*
time
.
Second
,
b
.
backend
.
RPCGasCap
())
status
:=
hexutil
.
Uint64
(
1
)
if
failed
{
status
=
0
...
...
@@ -832,17 +791,13 @@ func (b *Block) Call(ctx context.Context, args struct {
func
(
b
*
Block
)
EstimateGas
(
ctx
context
.
Context
,
args
struct
{
Data
ethapi
.
CallArgs
})
(
hexutil
.
Uint64
,
error
)
{
err
:=
b
.
onMainChain
(
ctx
)
if
err
!=
nil
{
return
hexutil
.
Uint64
(
0
),
err
}
if
b
.
num
==
nil
{
if
b
.
numberOrHash
==
nil
{
_
,
err
:=
b
.
resolveHeader
(
ctx
)
if
err
!=
nil
{
return
hexutil
.
Uint64
(
0
),
err
}
}
gas
,
err
:=
ethapi
.
DoEstimateGas
(
ctx
,
b
.
backend
,
args
.
Data
,
*
b
.
num
,
b
.
backend
.
RPCGasCap
())
gas
,
err
:=
ethapi
.
DoEstimateGas
(
ctx
,
b
.
backend
,
args
.
Data
,
*
b
.
num
berOrHash
,
b
.
backend
.
RPCGasCap
())
return
gas
,
err
}
...
...
@@ -875,17 +830,19 @@ func (p *Pending) Transactions(ctx context.Context) (*[]*Transaction, error) {
func
(
p
*
Pending
)
Account
(
ctx
context
.
Context
,
args
struct
{
Address
common
.
Address
})
*
Account
{
pendingBlockNr
:=
rpc
.
BlockNumberOrHashWithNumber
(
rpc
.
PendingBlockNumber
)
return
&
Account
{
backend
:
p
.
backend
,
address
:
args
.
Address
,
blockN
umber
:
rpc
.
PendingBlockNumbe
r
,
blockN
rOrHash
:
pendingBlockN
r
,
}
}
func
(
p
*
Pending
)
Call
(
ctx
context
.
Context
,
args
struct
{
Data
ethapi
.
CallArgs
})
(
*
CallResult
,
error
)
{
result
,
gas
,
failed
,
err
:=
ethapi
.
DoCall
(
ctx
,
p
.
backend
,
args
.
Data
,
rpc
.
PendingBlockNumber
,
nil
,
vm
.
Config
{},
5
*
time
.
Second
,
p
.
backend
.
RPCGasCap
())
pendingBlockNr
:=
rpc
.
BlockNumberOrHashWithNumber
(
rpc
.
PendingBlockNumber
)
result
,
gas
,
failed
,
err
:=
ethapi
.
DoCall
(
ctx
,
p
.
backend
,
args
.
Data
,
pendingBlockNr
,
nil
,
vm
.
Config
{},
5
*
time
.
Second
,
p
.
backend
.
RPCGasCap
())
status
:=
hexutil
.
Uint64
(
1
)
if
failed
{
status
=
0
...
...
@@ -900,7 +857,8 @@ func (p *Pending) Call(ctx context.Context, args struct {
func
(
p
*
Pending
)
EstimateGas
(
ctx
context
.
Context
,
args
struct
{
Data
ethapi
.
CallArgs
})
(
hexutil
.
Uint64
,
error
)
{
return
ethapi
.
DoEstimateGas
(
ctx
,
p
.
backend
,
args
.
Data
,
rpc
.
PendingBlockNumber
,
p
.
backend
.
RPCGasCap
())
pendingBlockNr
:=
rpc
.
BlockNumberOrHashWithNumber
(
rpc
.
PendingBlockNumber
)
return
ethapi
.
DoEstimateGas
(
ctx
,
p
.
backend
,
args
.
Data
,
pendingBlockNr
,
p
.
backend
.
RPCGasCap
())
}
// Resolver is the top-level object in the GraphQL hierarchy.
...
...
@@ -914,24 +872,23 @@ func (r *Resolver) Block(ctx context.Context, args struct {
})
(
*
Block
,
error
)
{
var
block
*
Block
if
args
.
Number
!=
nil
{
num
:=
rpc
.
BlockNumber
(
uint64
(
*
args
.
Number
))
number
:=
rpc
.
BlockNumber
(
uint64
(
*
args
.
Number
))
numberOrHash
:=
rpc
.
BlockNumberOrHashWithNumber
(
number
)
block
=
&
Block
{
backend
:
r
.
backend
,
num
:
&
num
,
canonical
:
isCanonical
,
numberOrHash
:
&
numberOrHash
,
}
}
else
if
args
.
Hash
!=
nil
{
numberOrHash
:=
rpc
.
BlockNumberOrHashWithHash
(
*
args
.
Hash
,
false
)
block
=
&
Block
{
backend
:
r
.
backend
,
hash
:
*
args
.
Hash
,
canonical
:
unknown
,
numberOrHash
:
&
numberOrHash
,
}
}
else
{
num
:=
rpc
.
LatestBlockNumber
num
berOrHash
:=
rpc
.
BlockNumberOrHashWithNumber
(
rpc
.
LatestBlockNumber
)
block
=
&
Block
{
backend
:
r
.
backend
,
num
:
&
num
,
canonical
:
isCanonical
,
numberOrHash
:
&
numberOrHash
,
}
}
// Resolve the header, return nil if it doesn't exist.
...
...
@@ -963,11 +920,10 @@ func (r *Resolver) Blocks(ctx context.Context, args struct {
}
ret
:=
make
([]
*
Block
,
0
,
to
-
from
+
1
)
for
i
:=
from
;
i
<=
to
;
i
++
{
num
:=
i
num
berOrHash
:=
rpc
.
BlockNumberOrHashWithNumber
(
i
)
ret
=
append
(
ret
,
&
Block
{
backend
:
r
.
backend
,
num
:
&
num
,
canonical
:
isCanonical
,
numberOrHash
:
&
numberOrHash
,
})
}
return
ret
,
nil
...
...
internal/ethapi/api.go
View file @
ad03d980
...
...
@@ -530,8 +530,8 @@ func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 {
// GetBalance returns the amount of wei for the given address in the state of the
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
// block numbers are also allowed.
func
(
s
*
PublicBlockChainAPI
)
GetBalance
(
ctx
context
.
Context
,
address
common
.
Address
,
blockNr
rpc
.
BlockNumber
)
(
*
hexutil
.
Big
,
error
)
{
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
(
ctx
,
blockNr
)
func
(
s
*
PublicBlockChainAPI
)
GetBalance
(
ctx
context
.
Context
,
address
common
.
Address
,
blockNr
OrHash
rpc
.
BlockNumberOrHash
)
(
*
hexutil
.
Big
,
error
)
{
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
OrHash
(
ctx
,
blockNrOrHash
)
if
state
==
nil
||
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -555,8 +555,8 @@ type StorageResult struct {
}
// GetProof returns the Merkle-proof for a given account and optionally some storage keys.
func
(
s
*
PublicBlockChainAPI
)
GetProof
(
ctx
context
.
Context
,
address
common
.
Address
,
storageKeys
[]
string
,
blockNr
rpc
.
BlockNumber
)
(
*
AccountResult
,
error
)
{
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
(
ctx
,
blockNr
)
func
(
s
*
PublicBlockChainAPI
)
GetProof
(
ctx
context
.
Context
,
address
common
.
Address
,
storageKeys
[]
string
,
blockNr
OrHash
rpc
.
BlockNumberOrHash
)
(
*
AccountResult
,
error
)
{
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
OrHash
(
ctx
,
blockNrOrHash
)
if
state
==
nil
||
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -712,8 +712,8 @@ func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, bloc
}
// GetCode returns the code stored at the given address in the state for the given block number.
func
(
s
*
PublicBlockChainAPI
)
GetCode
(
ctx
context
.
Context
,
address
common
.
Address
,
blockNr
rpc
.
BlockNumber
)
(
hexutil
.
Bytes
,
error
)
{
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
(
ctx
,
blockNr
)
func
(
s
*
PublicBlockChainAPI
)
GetCode
(
ctx
context
.
Context
,
address
common
.
Address
,
blockNr
OrHash
rpc
.
BlockNumberOrHash
)
(
hexutil
.
Bytes
,
error
)
{
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
OrHash
(
ctx
,
blockNrOrHash
)
if
state
==
nil
||
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -724,8 +724,8 @@ func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Addres
// GetStorageAt returns the storage from the state at the given address, key and
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
// numbers are also allowed.
func
(
s
*
PublicBlockChainAPI
)
GetStorageAt
(
ctx
context
.
Context
,
address
common
.
Address
,
key
string
,
blockNr
rpc
.
BlockNumber
)
(
hexutil
.
Bytes
,
error
)
{
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
(
ctx
,
blockNr
)
func
(
s
*
PublicBlockChainAPI
)
GetStorageAt
(
ctx
context
.
Context
,
address
common
.
Address
,
key
string
,
blockNr
OrHash
rpc
.
BlockNumberOrHash
)
(
hexutil
.
Bytes
,
error
)
{
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
OrHash
(
ctx
,
blockNrOrHash
)
if
state
==
nil
||
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -757,10 +757,10 @@ type account struct {
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
)
{
func
DoCall
(
ctx
context
.
Context
,
b
Backend
,
args
CallArgs
,
blockNr
OrHash
rpc
.
BlockNumberOrHash
,
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
())
state
,
header
,
err
:=
b
.
StateAndHeaderByNumber
(
ctx
,
blockNr
)
state
,
header
,
err
:=
b
.
StateAndHeaderByNumber
OrHash
(
ctx
,
blockNrOrHash
)
if
state
==
nil
||
err
!=
nil
{
return
nil
,
0
,
false
,
err
}
...
...
@@ -874,16 +874,16 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
//
// 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
)
{
func
(
s
*
PublicBlockChainAPI
)
Call
(
ctx
context
.
Context
,
args
CallArgs
,
blockNr
OrHash
rpc
.
BlockNumberOrHash
,
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
())
result
,
_
,
_
,
err
:=
DoCall
(
ctx
,
s
.
b
,
args
,
blockNr
OrHash
,
accounts
,
vm
.
Config
{},
5
*
time
.
Second
,
s
.
b
.
RPCGasCap
())
return
(
hexutil
.
Bytes
)(
result
),
err
}
func
DoEstimateGas
(
ctx
context
.
Context
,
b
Backend
,
args
CallArgs
,
blockNr
rpc
.
BlockNumber
,
gasCap
*
big
.
Int
)
(
hexutil
.
Uint64
,
error
)
{
func
DoEstimateGas
(
ctx
context
.
Context
,
b
Backend
,
args
CallArgs
,
blockNr
OrHash
rpc
.
BlockNumberOrHash
,
gasCap
*
big
.
Int
)
(
hexutil
.
Uint64
,
error
)
{
// Binary search the gas requirement, as it may be higher than the amount used
var
(
lo
uint64
=
params
.
TxGas
-
1
...
...
@@ -894,7 +894,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
hi
=
uint64
(
*
args
.
Gas
)
}
else
{
// Retrieve the block to act as the gas ceiling
block
,
err
:=
b
.
BlockByNumber
(
ctx
,
blockNr
)
block
,
err
:=
b
.
BlockByNumber
OrHash
(
ctx
,
blockNrOrHash
)
if
err
!=
nil
{
return
0
,
err
}
...
...
@@ -910,7 +910,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
executable
:=
func
(
gas
uint64
)
bool
{
args
.
Gas
=
(
*
hexutil
.
Uint64
)(
&
gas
)
_
,
_
,
failed
,
err
:=
DoCall
(
ctx
,
b
,
args
,
rpc
.
PendingBlockNumber
,
nil
,
vm
.
Config
{},
0
,
gasCap
)
_
,
_
,
failed
,
err
:=
DoCall
(
ctx
,
b
,
args
,
blockNrOrHash
,
nil
,
vm
.
Config
{},
0
,
gasCap
)
if
err
!=
nil
||
failed
{
return
false
}
...
...
@@ -937,7 +937,8 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
// 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
CallArgs
)
(
hexutil
.
Uint64
,
error
)
{
return
DoEstimateGas
(
ctx
,
s
.
b
,
args
,
rpc
.
PendingBlockNumber
,
s
.
b
.
RPCGasCap
())
blockNrOrHash
:=
rpc
.
BlockNumberOrHashWithNumber
(
rpc
.
PendingBlockNumber
)
return
DoEstimateGas
(
ctx
,
s
.
b
,
args
,
blockNrOrHash
,
s
.
b
.
RPCGasCap
())
}
// ExecutionResult groups all structured logs emitted by the EVM
...
...
@@ -1224,9 +1225,9 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx cont
}
// GetTransactionCount returns the number of transactions the given address has sent for the given block number
func
(
s
*
PublicTransactionPoolAPI
)
GetTransactionCount
(
ctx
context
.
Context
,
address
common
.
Address
,
blockNr
rpc
.
BlockNumber
)
(
*
hexutil
.
Uint64
,
error
)
{
func
(
s
*
PublicTransactionPoolAPI
)
GetTransactionCount
(
ctx
context
.
Context
,
address
common
.
Address
,
blockNr
OrHash
rpc
.
BlockNumberOrHash
)
(
*
hexutil
.
Uint64
,
error
)
{
// Ask transaction pool for the nonce which includes pending transactions
if
blockNr
==
rpc
.
PendingBlockNumber
{
if
blockNr
,
ok
:=
blockNrOrHash
.
Number
();
ok
&&
blockNr
==
rpc
.
PendingBlockNumber
{
nonce
,
err
:=
s
.
b
.
GetPoolNonce
(
ctx
,
address
)
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -1234,7 +1235,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr
return
(
*
hexutil
.
Uint64
)(
&
nonce
),
nil
}
// Resolve block number and use its state to ask for the nonce
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
(
ctx
,
blockNr
)
state
,
_
,
err
:=
s
.
b
.
StateAndHeaderByNumber
OrHash
(
ctx
,
blockNrOrHash
)
if
state
==
nil
||
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -1405,7 +1406,8 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
Value
:
args
.
Value
,
Data
:
input
,
}
estimated
,
err
:=
DoEstimateGas
(
ctx
,
b
,
callArgs
,
rpc
.
PendingBlockNumber
,
b
.
RPCGasCap
())
pendingBlockNr
:=
rpc
.
BlockNumberOrHashWithNumber
(
rpc
.
PendingBlockNumber
)
estimated
,
err
:=
DoEstimateGas
(
ctx
,
b
,
callArgs
,
pendingBlockNr
,
b
.
RPCGasCap
())
if
err
!=
nil
{
return
err
}
...
...
internal/ethapi/backend.go
View file @
ad03d980
...
...
@@ -52,9 +52,12 @@ type Backend interface {
SetHead
(
number
uint64
)
HeaderByNumber
(
ctx
context
.
Context
,
number
rpc
.
BlockNumber
)
(
*
types
.
Header
,
error
)
HeaderByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
*
types
.
Header
,
error
)
HeaderByNumberOrHash
(
ctx
context
.
Context
,
blockNrOrHash
rpc
.
BlockNumberOrHash
)
(
*
types
.
Header
,
error
)
BlockByNumber
(
ctx
context
.
Context
,
number
rpc
.
BlockNumber
)
(
*
types
.
Block
,
error
)
BlockByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
*
types
.
Block
,
error
)
BlockByNumberOrHash
(
ctx
context
.
Context
,
blockNrOrHash
rpc
.
BlockNumberOrHash
)
(
*
types
.
Block
,
error
)
StateAndHeaderByNumber
(
ctx
context
.
Context
,
number
rpc
.
BlockNumber
)
(
*
state
.
StateDB
,
*
types
.
Header
,
error
)
StateAndHeaderByNumberOrHash
(
ctx
context
.
Context
,
blockNrOrHash
rpc
.
BlockNumberOrHash
)
(
*
state
.
StateDB
,
*
types
.
Header
,
error
)
GetReceipts
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
types
.
Receipts
,
error
)
GetTd
(
hash
common
.
Hash
)
*
big
.
Int
GetEVM
(
ctx
context
.
Context
,
msg
core
.
Message
,
state
*
state
.
StateDB
,
header
*
types
.
Header
)
(
*
vm
.
EVM
,
func
()
error
,
error
)
...
...
les/api_backend.go
View file @
ad03d980
...
...
@@ -65,6 +65,26 @@ func (b *LesApiBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
return
b
.
eth
.
blockchain
.
GetHeaderByNumberOdr
(
ctx
,
uint64
(
number
))
}
func
(
b
*
LesApiBackend
)
HeaderByNumberOrHash
(
ctx
context
.
Context
,
blockNrOrHash
rpc
.
BlockNumberOrHash
)
(
*
types
.
Header
,
error
)
{
if
blockNr
,
ok
:=
blockNrOrHash
.
Number
();
ok
{
return
b
.
HeaderByNumber
(
ctx
,
blockNr
)
}
if
hash
,
ok
:=
blockNrOrHash
.
Hash
();
ok
{
header
,
err
:=
b
.
HeaderByHash
(
ctx
,
hash
)
if
err
!=
nil
{
return
nil
,
err
}
if
header
==
nil
{
return
nil
,
errors
.
New
(
"header for hash not found"
)
}
if
blockNrOrHash
.
RequireCanonical
&&
b
.
eth
.
blockchain
.
GetCanonicalHash
(
header
.
Number
.
Uint64
())
!=
hash
{
return
nil
,
errors
.
New
(
"hash is not currently canonical"
)
}
return
header
,
nil
}
return
nil
,
errors
.
New
(
"invalid arguments; neither block nor hash specified"
)
}
func
(
b
*
LesApiBackend
)
HeaderByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
*
types
.
Header
,
error
)
{
return
b
.
eth
.
blockchain
.
GetHeaderByHash
(
hash
),
nil
}
...
...
@@ -81,6 +101,26 @@ func (b *LesApiBackend) BlockByHash(ctx context.Context, hash common.Hash) (*typ
return
b
.
eth
.
blockchain
.
GetBlockByHash
(
ctx
,
hash
)
}
func
(
b
*
LesApiBackend
)
BlockByNumberOrHash
(
ctx
context
.
Context
,
blockNrOrHash
rpc
.
BlockNumberOrHash
)
(
*
types
.
Block
,
error
)
{
if
blockNr
,
ok
:=
blockNrOrHash
.
Number
();
ok
{
return
b
.
BlockByNumber
(
ctx
,
blockNr
)
}
if
hash
,
ok
:=
blockNrOrHash
.
Hash
();
ok
{
block
,
err
:=
b
.
BlockByHash
(
ctx
,
hash
)
if
err
!=
nil
{
return
nil
,
err
}
if
block
==
nil
{
return
nil
,
errors
.
New
(
"header found, but block body is missing"
)
}
if
blockNrOrHash
.
RequireCanonical
&&
b
.
eth
.
blockchain
.
GetCanonicalHash
(
block
.
NumberU64
())
!=
hash
{
return
nil
,
errors
.
New
(
"hash is not currently canonical"
)
}
return
block
,
nil
}
return
nil
,
errors
.
New
(
"invalid arguments; neither block nor hash specified"
)
}
func
(
b
*
LesApiBackend
)
StateAndHeaderByNumber
(
ctx
context
.
Context
,
number
rpc
.
BlockNumber
)
(
*
state
.
StateDB
,
*
types
.
Header
,
error
)
{
header
,
err
:=
b
.
HeaderByNumber
(
ctx
,
number
)
if
err
!=
nil
{
...
...
@@ -92,6 +132,23 @@ func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
return
light
.
NewState
(
ctx
,
header
,
b
.
eth
.
odr
),
header
,
nil
}
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
{
header
:=
b
.
eth
.
blockchain
.
GetHeaderByHash
(
hash
)
if
header
==
nil
{
return
nil
,
nil
,
errors
.
New
(
"header for hash not found"
)
}
if
blockNrOrHash
.
RequireCanonical
&&
b
.
eth
.
blockchain
.
GetCanonicalHash
(
header
.
Number
.
Uint64
())
!=
hash
{
return
nil
,
nil
,
errors
.
New
(
"hash is not currently canonical"
)
}
return
light
.
NewState
(
ctx
,
header
,
b
.
eth
.
odr
),
header
,
nil
}
return
nil
,
nil
,
errors
.
New
(
"invalid arguments; neither block nor hash specified"
)
}
func
(
b
*
LesApiBackend
)
GetReceipts
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
types
.
Receipts
,
error
)
{
if
number
:=
rawdb
.
ReadHeaderNumber
(
b
.
eth
.
chainDb
,
hash
);
number
!=
nil
{
return
light
.
GetBlockReceipts
(
ctx
,
b
.
eth
.
odr
,
hash
,
*
number
)
...
...
light/lightchain.go
View file @
ad03d980
...
...
@@ -426,6 +426,11 @@ func (lc *LightChain) HasHeader(hash common.Hash, number uint64) bool {
return
lc
.
hc
.
HasHeader
(
hash
,
number
)
}
// GetCanonicalHash returns the canonical hash for a given block number
func
(
bc
*
LightChain
)
GetCanonicalHash
(
number
uint64
)
common
.
Hash
{
return
bc
.
hc
.
GetCanonicalHash
(
number
)
}
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
// hash, fetching towards the genesis block.
func
(
lc
*
LightChain
)
GetBlockHashesFromHash
(
hash
common
.
Hash
,
max
uint64
)
[]
common
.
Hash
{
...
...
rpc/types.go
View file @
ad03d980
...
...
@@ -18,10 +18,12 @@ package rpc
import
(
"context"
"encoding/json"
"fmt"
"math"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
...
...
@@ -105,3 +107,94 @@ 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
,
}
}
rpc/types_test.go
View file @
ad03d980
...
...
@@ -20,6 +20,7 @@ import (
"encoding/json"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
)
...
...
@@ -64,3 +65,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
)
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment