MisUse of headHash as blockHash when create EVM context
louisliu2048 opened this issue · 1 comments
louisliu2048 commented
System info: [Include Ethermint commit, operating system name, and other relevant details]
When Create EVM, we will pass a getHash function to the evm context:
func (st StateTransition) newEVM(
ctx sdk.Context,
csdb *CommitStateDB,
gasLimit uint64,
gasPrice *big.Int,
config ChainConfig,
extraEIPs []int,
) *vm.EVM {
// Create context for evm
blockCtx := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetHash: GetHashFn(ctx, csdb),
Coinbase: common.Address{}, // there's no beneficiary since we're not mining
BlockNumber: big.NewInt(ctx.BlockHeight()),
Time: big.NewInt(ctx.BlockHeader().Time.Unix()),
Difficulty: big.NewInt(0), // unused. Only required in PoW context
GasLimit: gasLimit,
}
...
}
in the GetHashFn,when the require height is the current block height, it will return the current Block's head hash, but not the blockHash
// GetHashFn implements vm.GetHashFunc for Ethermint. It handles 3 cases:
// 1. The requested height matches the current height from context (and thus same epoch number)
// 2. The requested height is from an previous height from the same chain epoch
// 3. The requested height is from a height greater than the latest one
func GetHashFn(ctx sdk.Context, csdb *CommitStateDB) vm.GetHashFunc {
return func(height uint64) common.Hash {
switch {
case ctx.BlockHeight() == int64(height):
// Case 1: The requested height matches the one from the context so we can retrieve the header
// hash directly from the context.
return HashFromContext(ctx)
case ctx.BlockHeight() > int64(height):
// Case 2: if the chain is not the current height we need to retrieve the hash from the store for the
// current chain epoch. This only applies if the current height is greater than the requested height.
return csdb.WithContext(ctx).GetHeightHash(height)
default:
// Case 3: heights greater than the current one returns an empty hash.
return common.Hash{}
}
}
}
this would lead to something wrong for we can only get the block detail with blockHash, not headHash.
Steps to reproduce:
- [First Step]
- [Second Step]
- [and so on...]
Expected behavior: [What you expected to happen]
always return BlockHash, not HeadHash
Actual behavior: [What actually happened]
Additional info: [Include gist of relevant config, logs, etc.]
summerpro commented
Problem reproduction process
1. deploy this contract to ethermint network with branch development by remix
pragma solidity =0.6.6;
contract Test{
event Test1(address indexed user);
function T1(uint256 a, uint256 b) public {
for (uint256 i = 0; i< 10; i++) {
b = a + b;
}
emit Test1(msg.sender);
}
2. transfer the function T1
3. call the rpc api eth_getLogs
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x1","address":"0x1d29789a81aa381fE5830cd378Bb8F5c76E8C8a7"}],"id":1}' -H "Content-Type: application/json" http://localhost:8545
// "address" should be contract address of the solidity code.
4. get the block hash from logs
5. query block message by block hash, but the block hash are not correct hash, it will return empty.
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0x1b9911f57c13e5160d567ea6cf5b545413f96b95e43ec6e02787043351fb2cc4", false],"id":1}' -H "Content-Type: application/json" http://localhost:8545
root case
1. block hash from Logs are set by CommitStateDB.bhash
// AddLog adds a new log to the state and sets the log metadata from the state.
func (csdb *CommitStateDB) AddLog(log *ethtypes.Log) {
csdb.journal.append(addLogChange{txhash: csdb.thash})
log.TxHash = csdb.thash
log.BlockHash = csdb.BHash
log.TxIndex = uint(csdb.txIndex)
log.Index = csdb.logSize
logs, err := csdb.GetLogs(csdb.thash)
if err != nil {
// panic on unmarshal error
panic(err)
}
if err = csdb.SetLogs(csdb.thash, append(logs, log)); err != nil {
// panic on marshal error
panic(err)
}
}
2. CommitStateDB.bhash are set by function HashFromContext, and the function return the header hash but not block hash
blockHash := types.HashFromContext(ctx)
k.CommitStateDB.Prepare(ethHash, blockHash, k.TxCount)