mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
fix block hash cache
This commit is contained in:
parent
cc1158ae6d
commit
2690445207
2 changed files with 118 additions and 23 deletions
|
|
@ -1322,8 +1322,8 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo
|
|||
blockContext = core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil)
|
||||
rules = s.b.ChainConfig().Rules(blockContext.BlockNumber, blockContext.Random != nil, blockContext.Time)
|
||||
precompiles = vm.ActivePrecompiledContracts(rules).Copy()
|
||||
numHashes = headers[len(headers)-1].Number.Uint64() - base.Number.Uint64()
|
||||
// Cache for simulated and phantom block hashes.
|
||||
numHashes = headers[len(headers)-1].Number.Uint64() - base.Number.Uint64() + 256
|
||||
// Cache for the block hashes.
|
||||
hashes = make([]common.Hash, numHashes)
|
||||
)
|
||||
for bi, block := range blocks {
|
||||
|
|
@ -1426,21 +1426,35 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo
|
|||
// 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 returns the index of the hash in the hashes cache.
|
||||
// The cache potentially includes 255 blocks prior to the base.
|
||||
getIndex := func(n uint64) int {
|
||||
return int(n - base.Number.Uint64())
|
||||
first := base.Number.Uint64() - 255
|
||||
return int(n - first)
|
||||
}
|
||||
index := getIndex(n)
|
||||
if h := hashes[index]; h != (common.Hash{}) {
|
||||
return h, hashes, nil
|
||||
}
|
||||
h, err := computeHash(ctx, n, base, headers, backend, hashes)
|
||||
if err != nil {
|
||||
return common.Hash{}, hashes, err
|
||||
}
|
||||
if h != (common.Hash{}) {
|
||||
hashes[index] = h
|
||||
}
|
||||
return h, hashes, nil
|
||||
}
|
||||
|
||||
func computeHash(ctx context.Context, n uint64, base *types.Header, headers []*types.Header, backend Backend, hashes []common.Hash) (common.Hash, error) {
|
||||
if n == base.Number.Uint64() {
|
||||
return base.Hash(), hashes, nil
|
||||
return base.Hash(), 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 common.Hash{}, fmt.Errorf("failed to load block hash for number %d. Err: %v\n", n, err)
|
||||
}
|
||||
return h.Hash(), hashes, nil
|
||||
return h.Hash(), nil
|
||||
}
|
||||
h := base
|
||||
for i, _ := range headers {
|
||||
|
|
@ -1449,29 +1463,23 @@ func getHash(ctx context.Context, n uint64, base *types.Header, headers []*types
|
|||
// so no need to check that condition.
|
||||
if tmp.Number.Uint64() == n {
|
||||
hash := tmp.Hash()
|
||||
hashes[index] = hash
|
||||
return hash, hashes, nil
|
||||
return hash, nil
|
||||
} else if tmp.Number.Uint64() > n {
|
||||
// Phantom block.
|
||||
var lastNonPhantomHash common.Hash
|
||||
if hash := hashes[getIndex(h.Number.Uint64())]; hash != (common.Hash{}) {
|
||||
lastNonPhantomHash = hash
|
||||
} else {
|
||||
lastNonPhantomHash = h.Hash()
|
||||
hashes[getIndex(h.Number.Uint64())] = lastNonPhantomHash
|
||||
lastNonPhantomHash, _, err := getHash(ctx, h.Number.Uint64(), base, headers, backend, hashes)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
// keccak(rlp(lastNonPhantomBlockHash, blockNumber))
|
||||
hashData, err := rlp.EncodeToBytes([][]byte{lastNonPhantomHash.Bytes(), big.NewInt(int64(n)).Bytes()})
|
||||
if err != nil {
|
||||
return common.Hash{}, hashes, err
|
||||
return common.Hash{}, err
|
||||
}
|
||||
hash := crypto.Keccak256Hash(hashData)
|
||||
hashes[index] = hash
|
||||
return hash, hashes, nil
|
||||
return crypto.Keccak256Hash(hashData), nil
|
||||
}
|
||||
h = tmp
|
||||
}
|
||||
return common.Hash{}, hashes, errors.New("requested block is in future")
|
||||
return common.Hash{}, errors.New("requested block is in future")
|
||||
}
|
||||
|
||||
// repairLogs updates the block hash in the logs present in a multicall
|
||||
|
|
|
|||
|
|
@ -1640,6 +1640,91 @@ func TestMulticallV1(t *testing.T) {
|
|||
}},
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "blockhash-opcode",
|
||||
tag: latest,
|
||||
blocks: []CallBatch{{
|
||||
BlockOverrides: &BlockOverrides{
|
||||
Number: (*hexutil.Big)(big.NewInt(12)),
|
||||
},
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[2].addr: {
|
||||
Code: hex2Bytes("600035804060008103601057600080fd5b5050"),
|
||||
},
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
From: &accounts[0].addr,
|
||||
To: &randomAccounts[2].addr,
|
||||
// Phantom block after base.
|
||||
Input: uint256ToBytes(uint256.NewInt(11)),
|
||||
}, {
|
||||
From: &accounts[0].addr,
|
||||
To: &randomAccounts[2].addr,
|
||||
// Canonical block.
|
||||
Input: uint256ToBytes(uint256.NewInt(8)),
|
||||
}, {
|
||||
From: &accounts[0].addr,
|
||||
To: &randomAccounts[2].addr,
|
||||
// base block.
|
||||
Input: uint256ToBytes(uint256.NewInt(10)),
|
||||
}},
|
||||
}, {
|
||||
BlockOverrides: &BlockOverrides{
|
||||
Number: (*hexutil.Big)(big.NewInt(16)),
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
From: &accounts[0].addr,
|
||||
To: &randomAccounts[2].addr,
|
||||
// blocks[0]
|
||||
Input: uint256ToBytes(uint256.NewInt(12)),
|
||||
}, {
|
||||
From: &accounts[0].addr,
|
||||
To: &randomAccounts[2].addr,
|
||||
// Phantom after blocks[0]
|
||||
Input: uint256ToBytes(uint256.NewInt(13)),
|
||||
}},
|
||||
}},
|
||||
want: []blockRes{{
|
||||
Number: "0xc",
|
||||
GasLimit: "0x47e7c4",
|
||||
GasUsed: "0xf864",
|
||||
FeeRecipient: coinbase,
|
||||
Calls: []callRes{{
|
||||
ReturnValue: "0x",
|
||||
GasUsed: "0x52cc",
|
||||
Logs: []log{},
|
||||
Status: "0x1",
|
||||
}, {
|
||||
ReturnValue: "0x",
|
||||
GasUsed: "0x52cc",
|
||||
Logs: []log{},
|
||||
Status: "0x1",
|
||||
}, {
|
||||
|
||||
ReturnValue: "0x",
|
||||
GasUsed: "0x52cc",
|
||||
Logs: []log{},
|
||||
Status: "0x1",
|
||||
}},
|
||||
}, {
|
||||
Number: "0x10",
|
||||
GasLimit: "0x47e7c4",
|
||||
GasUsed: "0xa598",
|
||||
FeeRecipient: coinbase,
|
||||
Calls: []callRes{{
|
||||
ReturnValue: "0x",
|
||||
GasUsed: "0x52cc",
|
||||
Logs: []log{},
|
||||
Status: "0x1",
|
||||
}, {
|
||||
|
||||
ReturnValue: "0x",
|
||||
GasUsed: "0x52cc",
|
||||
Logs: []log{},
|
||||
Status: "0x1",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testSuite {
|
||||
|
|
@ -1715,6 +1800,12 @@ func newBytes(b []byte) *hexutil.Bytes {
|
|||
return &rpcBytes
|
||||
}
|
||||
|
||||
func uint256ToBytes(v *uint256.Int) *hexutil.Bytes {
|
||||
b := v.Bytes32()
|
||||
r := hexutil.Bytes(b[:])
|
||||
return &r
|
||||
}
|
||||
|
||||
func TestRPCMarshalBlock(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
|
|
@ -1924,10 +2015,6 @@ func TestRPCMarshalBlock(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func hex2Hash(s string) common.Hash {
|
||||
return common.BytesToHash(common.FromHex(s))
|
||||
}
|
||||
|
||||
func TestRPCGetBlockOrHeader(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue