Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/evm: Random opcode (EIP-4399) #24141

Merged
merged 12 commits into from Jan 10, 2022

Conversation

MariusVanDerWijden
Copy link
Member

This PR implements EIP-4399, the RANDOM opcode post-merge.
Since we don't know the merge block number beforehand, we need to somehow signal to the EVM that the Random opcode should be used now. This is currently done by setting the isMerge to true which is done in the block context, if the block has a difficulty of 0.

Additionally I extended the StateTestUtil to be able to create state tests with the RANDOM opcode. An example for that later.

replaces #23985, #24068

Copy link
Contributor

@holiman holiman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks kind of ok, but not sure -- maybe it can be done even simpler, somehow...

core/vm/opcodes.go Show resolved Hide resolved
eth/catalyst/api.go Outdated Show resolved Hide resolved
@@ -99,6 +99,7 @@ const (
CHAINID OpCode = 0x46
SELFBALANCE OpCode = 0x47
BASEFEE OpCode = 0x48
RANDOM OpCode = 0x44 // Same as DIFFICULTY
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep the sort order

tests/state_test_util.go Outdated Show resolved Hide resolved
if t.json.Env.Random != nil {
// Post-Merge
genesis.Mixhash = common.BigToHash(t.json.Env.Random)
genesis.Difficulty = nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nil or 0?

core/evm.go Outdated
@@ -61,6 +61,8 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
Difficulty: new(big.Int).Set(header.Difficulty),
BaseFee: baseFee,
GasLimit: header.GasLimit,
Random: header.MixDigest,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick, I think we should keep this as nil before the merge, just to catch any code accidentally touching this field prematurely.

core/evm.go Outdated
@@ -61,6 +61,8 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
Difficulty: new(big.Int).Set(header.Difficulty),
BaseFee: baseFee,
GasLimit: header.GasLimit,
Random: header.MixDigest,
IsPostMerge: header.Difficulty.Cmp(common.Big0) == 0,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this as a field though? We do pass in the difficult anyway, couldn't we just compare in there? Or look at the random field and see if it's set or not?

core/vm/evm.go Outdated
@@ -75,6 +75,8 @@ type BlockContext struct {
Time *big.Int // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY
BaseFee *big.Int // Provides information for BASEFEE
Random common.Hash // Provides information for RANDOM
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't we have this be *common.Hash and use it as a signal for pre/post-merge-ness?

@marioevz
Copy link
Member

marioevz commented Jan 5, 2022

I'm currently testing using the following:
env.json:

{
    "currentCoinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
    "currentNumber" : "0x01",
    "currentTimestamp" : "0x54c99069",
    "currentGasLimit" : "0x2fefd8",
    "currentDifficulty": "0x00",
    "currentRandom": "0x1234",
    "previousHash" : "0x3daadbe27e1a67dff067351fdbee364ea0b8d16d3a6fb6bc46c08920a4de3571",
    "parentTimestamp" : "0x54c98c81",
    "parentDifficulty" : "0x00",
    "parentUncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "blockHashes" : {
        "0" : "0x3daadbe27e1a67dff067351fdbee364ea0b8d16d3a6fb6bc46c08920a4de3571"
    }
}

alloc.json:

{
    "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
        "balance" : "0x02540be400",
        "nonce" : "0x00",
        "code" : "0x",
        "storage" : {
        }
    },
    "0xcccccccccccccccccccccccccccccccccccccccc" : {
        "balance" : "0x0ba1a9ce",
        "nonce" : "0x00",
        "code" : "0x44600155",
        "storage" : {
        }
    }
}

txs.rlp:

"0xf864f862808203e88307a12094cccccccccccccccccccccccccccccccccccccccc80801ca03d518a9d5e1534b8b2dabd3a9d1bd14ce86f5558b55165b8516bf5e88e5a8d63a034fef66ee73b4992ddca7591573c3f51bded86233317eaa9738dcc6e6ab17f47"

With the evm command:
/bin/evm t8n --state.fork Berlin --state.reward 2000000000000000000 --input.alloc alloc.json --input.txs txs.rlp --input.env env.json --output.basedir ./ --output.result out.json --output.alloc outAlloc.json

And expect to see the storage set to the value of currentRandom, but the storage is unset in the output.
Increasing currentDifficulty to any value greater than zero results in that value being stored instead.

@MariusVanDerWijden
Copy link
Member Author

@marioevz I have the following state test:

{"FuzzyVM-37426906-1385711810":
{"env":{"currentCoinbase":"b94f5374fce5edbc8e2a8697c15331677e6ebf0b","currentRandom":"0x1000000000000000000000000000000000000000000000000000000000000001","currentGasLimit":"0x26e1f476fe1e22","currentNumber":"0x1",
"currentTimestamp":"0x3e8","currentBaseFee":"0x3B","previousHash":"0x000000000000000000000000000000000000000000000000000000000000000"},
"pre":{
    "0x00000000000000000000000000000000b0b0face": {"code":"0x40600052","storage":{},"balance":"0x0","nonce":"0x0"},
    "0x000000000000000000000000000000ca1100f022": {"code":"0x444455","storage":{},"balance":"0x0","nonce":"0x0"},
    "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b":{"code":"0x","storage":{},"balance":"0x3fffffffffffffff","nonce":"0x0"}
    },
"transaction":{"gasPrice":"0x80","nonce":"0x0","to":"0x000000000000000000000000000000ca1100f022","data":[""],"gasLimit":["0x1312d00"],"value":["0xec43921b"],"secretKey":"0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"}
,"out":"0x","post":{
    "London":[{"hash":"63f729142596e783fee36c8db6d47db30783290dc33073d242108baf0281ca71","logs":"1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "indexes":{"data":0,"gas":0,"value":0}}]
    }}}

which produces

> ~/go/src/github.com/ethereum/go-ethereum/build/bin/evm --debug  statetest 4399.json
#### TRACE ####
DIFFICULTY      pc=00000000 gas=19979000 cost=2

DIFFICULTY      pc=00000001 gas=19978998 cost=2
Stack:
00000000  0x1000000000000000000000000000000000000000000000000000000000000001

SSTORE          pc=00000002 gas=19978996 cost=22100
Stack:
00000000  0x1000000000000000000000000000000000000000000000000000000000000001
00000001  0x1000000000000000000000000000000000000000000000000000000000000001
Storage:
1000000000000000000000000000000000000000000000000000000000000001: 1000000000000000000000000000000000000000000000000000000000000001

STOP            pc=00000003 gas=19956896 cost=0

[
  {
    "name": "FuzzyVM-37426906-1385711810",
    "pass": true,
    "fork": "London"
  }
]

@MariusVanDerWijden
Copy link
Member Author

Found and fixed:

{
 "0x8888f1f195afa192cfee860698584c030f4c9db1": {
  "balance": "0x1bc16d675159bae8"
 },
 "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
  "balance": "0x2517a2918",
  "nonce": "0x1"
 },
 "0xcccccccccccccccccccccccccccccccccccccccc": {
  "code": "0x44600155",
  "storage": {
   "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000001234"
  },
  "balance": "0xba1a9ce"
 }
}⏎ 

Thanks for noticing @marioevz !

tests/state_test_util.go Outdated Show resolved Hide resolved
Copy link
Member

@karalabe karalabe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM

@karalabe karalabe added this to the 1.10.16 milestone Jan 10, 2022
@karalabe
Copy link
Member

Wondering long term if we could "revert" this extra flag to use block numbers. Would be tempted to say after the merge after the block number is finalized, but that would prevent other networks from switching over. Hmm, maybe we can just let other networks switch over based on block number? Probably no because of the TTD. Ugh.

@karalabe karalabe merged commit b1e72f7 into ethereum:master Jan 10, 2022
@MariusVanDerWijden
Copy link
Member Author

I would also say that we should revert it once we have a block height. We might even hardcode the terminal blockhash for mainnet afterwards

sidhujag pushed a commit to syscoin/go-ethereum that referenced this pull request Jan 11, 2022
ValentinTrinque pushed a commit to vegaprotocol/go-ethereum that referenced this pull request Jan 25, 2022
* core: implement eip-4399 random opcode

* core: make vmconfig threadsafe

* core: miner: pass vmConfig by value not reference

* all: enable 4399 by Rules

* core: remove diff (f)

* tests: set proper difficulty (f)

* smaller diff (f)

* eth/catalyst: nit

* core: make RANDOM a pointer which is only set post-merge

* cmd/evm/internal/t8ntool: fix t8n tracing of 4399

* tests: set difficulty

* cmd/evm/internal/t8ntool: check that baserules are london before applying the merge chainrules
JacekGlen pushed a commit to JacekGlen/go-ethereum that referenced this pull request May 26, 2022
* core: implement eip-4399 random opcode

* core: make vmconfig threadsafe

* core: miner: pass vmConfig by value not reference

* all: enable 4399 by Rules

* core: remove diff (f)

* tests: set proper difficulty (f)

* smaller diff (f)

* eth/catalyst: nit

* core: make RANDOM a pointer which is only set post-merge

* cmd/evm/internal/t8ntool: fix t8n tracing of 4399

* tests: set difficulty

* cmd/evm/internal/t8ntool: check that baserules are london before applying the merge chainrules
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants