Skip to content
This repository has been archived by the owner on Nov 30, 2021. It is now read-only.

MisUse of headHash as blockHash when create EVM context #775

Closed
louisliu2048 opened this issue Feb 4, 2021 · 1 comment · Fixed by #780
Closed

MisUse of headHash as blockHash when create EVM context #775

louisliu2048 opened this issue Feb 4, 2021 · 1 comment · Fixed by #780

Comments

@louisliu2048
Copy link

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:

  1. [First Step]
  2. [Second Step]
  3. [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
Copy link
Contributor

summerpro commented Feb 13, 2021

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

image

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)

freddyli7 pushed a commit that referenced this issue Apr 20, 2021
@freddyli7 freddyli7 mentioned this issue Apr 20, 2021
11 tasks
freddyli7 added a commit that referenced this issue Apr 20, 2021
* merge pr #775

* unit test fix

Co-authored-by: Freddy Li <[email protected]>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants