mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
serve blockhash requests
This commit is contained in:
parent
973116c1d2
commit
a5ffd9adf2
1 changed files with 82 additions and 29 deletions
|
|
@ -1290,7 +1290,7 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo
|
||||||
n := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
n := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||||
blockNrOrHash = &n
|
blockNrOrHash = &n
|
||||||
}
|
}
|
||||||
state, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, *blockNrOrHash)
|
state, base, err := s.b.StateAndHeaderByNumberOrHash(ctx, *blockNrOrHash)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1309,7 +1309,7 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo
|
||||||
// Make sure the context is cancelled when the call has completed
|
// Make sure the context is cancelled when the call has completed
|
||||||
// this makes sure resources are cleaned up.
|
// this makes sure resources are cleaned up.
|
||||||
defer cancel()
|
defer cancel()
|
||||||
headers, err := makeHeaders(ctx, s.b.ChainConfig(), blocks, header)
|
headers, err := makeHeaders(ctx, s.b.ChainConfig(), blocks, base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1318,25 +1318,34 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo
|
||||||
// Each tx and all the series of txes shouldn't consume more gas than cap
|
// Each tx and all the series of txes shouldn't consume more gas than cap
|
||||||
globalGasCap = s.b.RPCGasCap()
|
globalGasCap = s.b.RPCGasCap()
|
||||||
gp = new(core.GasPool).AddGas(globalGasCap)
|
gp = new(core.GasPool).AddGas(globalGasCap)
|
||||||
|
header = base
|
||||||
blockContext = core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil)
|
blockContext = core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil)
|
||||||
rules = s.b.ChainConfig().Rules(blockContext.BlockNumber, blockContext.Random != nil, blockContext.Time)
|
rules = s.b.ChainConfig().Rules(blockContext.BlockNumber, blockContext.Random != nil, blockContext.Time)
|
||||||
precompiles = vm.ActivePrecompiledContracts(rules).Copy()
|
precompiles = vm.ActivePrecompiledContracts(rules).Copy()
|
||||||
|
numHashes = headers[len(headers)-1].Number.Uint64() - base.Number.Uint64()
|
||||||
|
// Cache for simulated and phantom block hashes.
|
||||||
|
hashes = make([]common.Hash, numHashes)
|
||||||
)
|
)
|
||||||
for bi, block := range blocks {
|
for bi, block := range blocks {
|
||||||
prevHeader := header
|
|
||||||
header = headers[bi]
|
header = headers[bi]
|
||||||
blockContext = core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil)
|
blockContext = core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil)
|
||||||
blockContext.GetHash = func(uint64) common.Hash {
|
// Respond to BLOCKHASH requests.
|
||||||
// TODO
|
blockContext.GetHash = func(n uint64) common.Hash {
|
||||||
return header.Hash()
|
var (
|
||||||
|
h common.Hash
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
h, hashes, err = getHash(ctx, n, base, headers, s.b, hashes)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn(err.Error())
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
return h
|
||||||
}
|
}
|
||||||
// TODO: GetHashFn
|
|
||||||
hash := crypto.Keccak256Hash(blockContext.BlockNumber.Bytes())
|
|
||||||
// State overrides are applied prior to execution of a block
|
// State overrides are applied prior to execution of a block
|
||||||
if err := block.StateOverrides.Apply(state, precompiles); err != nil {
|
if err := block.StateOverrides.Apply(state, precompiles); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
gasUsed uint64
|
gasUsed uint64
|
||||||
txes = make([]*types.Transaction, len(block.Calls))
|
txes = make([]*types.Transaction, len(block.Calls))
|
||||||
|
|
@ -1365,7 +1374,8 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo
|
||||||
// TODO: repair log block hashes post execution.
|
// TODO: repair log block hashes post execution.
|
||||||
vmConfig := &vm.Config{
|
vmConfig := &vm.Config{
|
||||||
NoBaseFee: true,
|
NoBaseFee: true,
|
||||||
Tracer: newTracer(opts.TraceTransfers, blockContext.BlockNumber.Uint64(), hash, tx.Hash(), uint(i)),
|
// Block hash will be repaired after execution.
|
||||||
|
Tracer: newTracer(opts.TraceTransfers, blockContext.BlockNumber.Uint64(), common.Hash{}, tx.Hash(), uint(i)),
|
||||||
}
|
}
|
||||||
result, err := applyMessage(ctx, s.b, call, state, header, timeout, gp, &blockContext, vmConfig, precompiles, opts.Validation)
|
result, err := applyMessage(ctx, s.b, call, state, header, timeout, gp, &blockContext, vmConfig, precompiles, opts.Validation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1393,10 +1403,15 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo
|
||||||
gasUsed += result.UsedGas
|
gasUsed += result.UsedGas
|
||||||
state.Finalise(true)
|
state.Finalise(true)
|
||||||
}
|
}
|
||||||
// If last non-phantom block is parent of current block, set parent hash.
|
var (
|
||||||
if header.Number.Uint64()-prevHeader.Number.Uint64() == 1 {
|
parentHash common.Hash
|
||||||
header.ParentHash = prevHeader.Hash()
|
err error
|
||||||
|
)
|
||||||
|
parentHash, hashes, err = getHash(ctx, header.Number.Uint64()-1, base, headers, s.b, hashes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
header.ParentHash = parentHash
|
||||||
header.Root = state.IntermediateRoot(true)
|
header.Root = state.IntermediateRoot(true)
|
||||||
header.GasUsed = gasUsed
|
header.GasUsed = gasUsed
|
||||||
header.TxHash = types.DeriveSha(types.Transactions(txes), trie.NewStackTrie(nil))
|
header.TxHash = types.DeriveSha(types.Transactions(txes), trie.NewStackTrie(nil))
|
||||||
|
|
@ -1406,6 +1421,59 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getHash returns the hash for the block of the given number. Block can be
|
||||||
|
// part of the canonical chain, a simulated block or a phantom block.
|
||||||
|
// Note getHash assumes `n` is smaller than the last already simulated block
|
||||||
|
// and smaller than the last block to be simulated.
|
||||||
|
func getHash(ctx context.Context, n uint64, base *types.Header, headers []*types.Header, backend Backend, hashes []common.Hash) (common.Hash, []common.Hash, error) {
|
||||||
|
getIndex := func(n uint64) int {
|
||||||
|
return int(n - base.Number.Uint64())
|
||||||
|
}
|
||||||
|
index := getIndex(n)
|
||||||
|
if h := hashes[index]; h != (common.Hash{}) {
|
||||||
|
return h, hashes, nil
|
||||||
|
}
|
||||||
|
if n == base.Number.Uint64() {
|
||||||
|
return base.Hash(), hashes, nil
|
||||||
|
} else if n < base.Number.Uint64() {
|
||||||
|
h, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(n))
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, hashes, fmt.Errorf("failed to load block hash for number %d. Err: %v\n", n, err)
|
||||||
|
}
|
||||||
|
return h.Hash(), hashes, nil
|
||||||
|
}
|
||||||
|
h := base
|
||||||
|
for i, _ := range headers {
|
||||||
|
tmp := headers[i]
|
||||||
|
// BLOCKHASH will only allow numbers prior to current block
|
||||||
|
// so no need to check that condition.
|
||||||
|
if tmp.Number.Uint64() == n {
|
||||||
|
hash := tmp.Hash()
|
||||||
|
hashes[index] = hash
|
||||||
|
return hash, hashes, nil
|
||||||
|
} else if tmp.Number.Uint64() > n {
|
||||||
|
// Phantom block.
|
||||||
|
var lastNonPhantomHash common.Hash
|
||||||
|
if hash := hashes[getIndex(h.Number.Uint64()-1)]; hash != (common.Hash{}) {
|
||||||
|
lastNonPhantomHash = hash
|
||||||
|
} else {
|
||||||
|
lastNonPhantomHash = h.Hash()
|
||||||
|
hashes[getIndex(h.Number.Uint64()-1)] = lastNonPhantomHash
|
||||||
|
}
|
||||||
|
// keccak(rlp(lastNonPhantomBlockHash, blockNumber))
|
||||||
|
hashData, err := rlp.EncodeToBytes([][]byte{lastNonPhantomHash.Bytes(), big.NewInt(int64(n)).Bytes()})
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, hashes, err
|
||||||
|
}
|
||||||
|
hash := crypto.Keccak256Hash(hashData)
|
||||||
|
hashes[index] = hash
|
||||||
|
return hash, hashes, nil
|
||||||
|
}
|
||||||
|
h = tmp
|
||||||
|
}
|
||||||
|
return common.Hash{}, hashes, errors.New("requested block is in future")
|
||||||
|
}
|
||||||
|
|
||||||
// repairLogs updates the block hash in the logs present in a multicall
|
// repairLogs updates the block hash in the logs present in a multicall
|
||||||
// result object. This is needed as during execution when logs are collected
|
// result object. This is needed as during execution when logs are collected
|
||||||
// the block hash is not known.
|
// the block hash is not known.
|
||||||
|
|
@ -1447,26 +1515,11 @@ func makeHeaders(ctx context.Context, config *params.ChainConfig, blocks []CallB
|
||||||
}
|
}
|
||||||
prevTimestamp = uint64(*overrides.Time)
|
prevTimestamp = uint64(*overrides.Time)
|
||||||
|
|
||||||
// ParentHash for non-phantom blocks can only be computed
|
var baseFee *big.Int
|
||||||
// after the previous block is executed.
|
|
||||||
var (
|
|
||||||
parentHash = common.Hash{}
|
|
||||||
baseFee *big.Int
|
|
||||||
)
|
|
||||||
// Calculate parentHash for phantom blocks.
|
|
||||||
if overrides.Number.ToInt().Uint64()-header.Number.Uint64() > 1 {
|
|
||||||
// keccak(rlp(lastNonPhantomBlockHash, blockNumber))
|
|
||||||
hashData, err := rlp.EncodeToBytes([][]byte{header.Hash().Bytes(), overrides.Number.ToInt().Bytes()})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
parentHash = crypto.Keccak256Hash(hashData)
|
|
||||||
}
|
|
||||||
if config.IsLondon(overrides.Number.ToInt()) {
|
if config.IsLondon(overrides.Number.ToInt()) {
|
||||||
baseFee = eip1559.CalcBaseFee(config, header)
|
baseFee = eip1559.CalcBaseFee(config, header)
|
||||||
}
|
}
|
||||||
header = &types.Header{
|
header = &types.Header{
|
||||||
ParentHash: parentHash,
|
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
Coinbase: base.Coinbase,
|
Coinbase: base.Coinbase,
|
||||||
Difficulty: base.Difficulty,
|
Difficulty: base.Difficulty,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue