Skip to content

Commit cc5f26b

Browse files
JonathanOppenheimerARR4Nalarso16StephenButtolph
authored
feat(cchain): support EIP-4788 parent beacon block root (#5586)
Signed-off-by: Jonathan Oppenheimer <147infiniti@gmail.com> Signed-off-by: Jonathan Oppenheimer <jonathan.oppenheimer@avalabs.org> Co-authored-by: Arran Schlosberg <519948+ARR4N@users.noreply.github.com> Co-authored-by: Austin Larson <78000745+alarso16@users.noreply.github.com> Co-authored-by: Stephen Buttolph <stephen@avalabs.org>
1 parent ef0f0b1 commit cc5f26b

10 files changed

Lines changed: 116 additions & 12 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ require (
2626
github.com/arr4n/shed v0.0.0-20260217105731-4cd15adfa100
2727
github.com/ava-labs/avalanchego/graft/coreth v1.14.2
2828
github.com/ava-labs/avalanchego/graft/subnet-evm v1.14.2
29-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf
29+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff
3030
github.com/btcsuite/btcd/btcutil v1.1.3
3131
github.com/cespare/xxhash/v2 v2.3.0
3232
github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,8 @@ github.com/arr4n/shed v0.0.0-20260217105731-4cd15adfa100 h1:j0Pj/Gq5XTbJEyzoSX82
335335
github.com/arr4n/shed v0.0.0-20260217105731-4cd15adfa100/go.mod h1:eD5UkxiWTdbkqM7mg2Xf981SAeWQ/Q80js/1rFcKpfg=
336336
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0 h1:JzmCHY9uQiZnrdmeXZ4s89g4Su0O4qs0EMmbOaHUDWw=
337337
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0/go.mod h1:3pf8KGfCmqegWoY5/pZ1NHUcyuRkfl/vHQuOjsdUtbI=
338-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf h1:B3pdQ3laHQ6UraKes0rHHUj0JNTGzQ5LOFVX43ePDpg=
339-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf/go.mod h1:6NxGoR1aLABnfLy+fncXRj0W6rUoUrXghnAWZ+Rhr4o=
338+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff h1:OEBrr1VL5yLS7NPNWmV+tUb8HduRGflAGnWVehDDMO0=
339+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff/go.mod h1:6NxGoR1aLABnfLy+fncXRj0W6rUoUrXghnAWZ+Rhr4o=
340340
github.com/ava-labs/simplex v0.0.0-20260429081342-03ce910391ad h1:P5IRndHUinfIZ73jdxl3M6jdcnKkQOLYvhGvE3VDiSU=
341341
github.com/ava-labs/simplex v0.0.0-20260429081342-03ce910391ad/go.mod h1:DADqV3zJ+ij8GqliStJ+aj9l/cPtb5ZUhNy5KxlDEsQ=
342342
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=

graft/coreth/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/ava-labs/avalanchego v1.14.2
1212
github.com/ava-labs/avalanchego/graft/evm v1.14.2
1313
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0
14-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf
14+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff
1515
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
1616
github.com/go-cmd/cmd v1.4.3
1717
github.com/google/go-cmp v0.7.0

graft/coreth/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ github.com/arr4n/shed v0.0.0-20260217105731-4cd15adfa100 h1:j0Pj/Gq5XTbJEyzoSX82
3030
github.com/arr4n/shed v0.0.0-20260217105731-4cd15adfa100/go.mod h1:eD5UkxiWTdbkqM7mg2Xf981SAeWQ/Q80js/1rFcKpfg=
3131
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0 h1:JzmCHY9uQiZnrdmeXZ4s89g4Su0O4qs0EMmbOaHUDWw=
3232
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0/go.mod h1:3pf8KGfCmqegWoY5/pZ1NHUcyuRkfl/vHQuOjsdUtbI=
33-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf h1:B3pdQ3laHQ6UraKes0rHHUj0JNTGzQ5LOFVX43ePDpg=
34-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf/go.mod h1:6NxGoR1aLABnfLy+fncXRj0W6rUoUrXghnAWZ+Rhr4o=
33+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff h1:OEBrr1VL5yLS7NPNWmV+tUb8HduRGflAGnWVehDDMO0=
34+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff/go.mod h1:6NxGoR1aLABnfLy+fncXRj0W6rUoUrXghnAWZ+Rhr4o=
3535
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
3636
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
3737
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=

graft/evm/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
github.com/VictoriaMetrics/fastcache v1.12.1
88
github.com/ava-labs/avalanchego v1.14.2
99
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0
10-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf
10+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff
1111
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
1212
github.com/deckarep/golang-set/v2 v2.1.0
1313
github.com/gorilla/rpc v1.2.0

graft/evm/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax
2121
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
2222
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0 h1:JzmCHY9uQiZnrdmeXZ4s89g4Su0O4qs0EMmbOaHUDWw=
2323
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0/go.mod h1:3pf8KGfCmqegWoY5/pZ1NHUcyuRkfl/vHQuOjsdUtbI=
24-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf h1:B3pdQ3laHQ6UraKes0rHHUj0JNTGzQ5LOFVX43ePDpg=
25-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf/go.mod h1:6NxGoR1aLABnfLy+fncXRj0W6rUoUrXghnAWZ+Rhr4o=
24+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff h1:OEBrr1VL5yLS7NPNWmV+tUb8HduRGflAGnWVehDDMO0=
25+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff/go.mod h1:6NxGoR1aLABnfLy+fncXRj0W6rUoUrXghnAWZ+Rhr4o=
2626
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
2727
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
2828
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=

graft/subnet-evm/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ require (
1212
github.com/ava-labs/avalanchego v1.14.2
1313
github.com/ava-labs/avalanchego/graft/evm v1.14.2
1414
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0
15-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf
15+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff
1616
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
1717
github.com/go-cmd/cmd v1.4.3
1818
github.com/gorilla/rpc v1.2.0

graft/subnet-evm/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
3030
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
3131
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0 h1:JzmCHY9uQiZnrdmeXZ4s89g4Su0O4qs0EMmbOaHUDWw=
3232
github.com/ava-labs/firewood-go-ethhash/ffi v0.7.0/go.mod h1:3pf8KGfCmqegWoY5/pZ1NHUcyuRkfl/vHQuOjsdUtbI=
33-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf h1:B3pdQ3laHQ6UraKes0rHHUj0JNTGzQ5LOFVX43ePDpg=
34-
github.com/ava-labs/libevm v1.13.15-0.20260622141141-097921408ecf/go.mod h1:6NxGoR1aLABnfLy+fncXRj0W6rUoUrXghnAWZ+Rhr4o=
33+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff h1:OEBrr1VL5yLS7NPNWmV+tUb8HduRGflAGnWVehDDMO0=
34+
github.com/ava-labs/libevm v1.13.15-0.20260629092640-7d62036142ff/go.mod h1:6NxGoR1aLABnfLy+fncXRj0W6rUoUrXghnAWZ+Rhr4o=
3535
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
3636
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
3737
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=

vms/saevm/saexec/execution.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ func Execute(
195195
b.CheckBaseFeeBound(baseFee)
196196
header.BaseFee = baseFee.ToBig()
197197

198+
// EIP-4788: before processing any transactions, store the parent beacon
199+
// block root, mirroring [core.StateProcessor.Process].
200+
core.SetBeaconBlockRoot(stateDB, header)
201+
198202
signer := b.Signer(config)
199203
gasPool := core.GasPool(math.MaxUint64) // required by geth but irrelevant so max it out
200204
var blockGasConsumed gas.Gas

vms/saevm/saexec/saexec_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"encoding/binary"
99
"fmt"
10+
"maps"
1011
"math"
1112
"math/big"
1213
"math/rand/v2"
@@ -83,6 +84,7 @@ type (
8384
hooks *saehookstest.Stub
8485
archival bool
8586
commitInterval uint64
87+
extraAlloc types.GenesisAlloc
8688
}
8789
sutOption = options.Option[sutConfig]
8890
)
@@ -106,6 +108,7 @@ func newSUT(tb testing.TB, opts ...sutOption) (context.Context, *SUT) {
106108

107109
wallet := saetest.NewUNSAFEWallet(tb, 1, types.LatestSigner(config))
108110
alloc := saetest.MaxAllocFor(wallet.Addresses()...)
111+
maps.Copy(alloc, sutCfg.extraAlloc)
109112

110113
genOpts := []blockstest.GenesisOption{
111114
blockstest.WithTrieDBConfig(tdbConfig),
@@ -157,6 +160,12 @@ func withHooks(h *saehookstest.Stub) sutOption {
157160
})
158161
}
159162

163+
func withExtraAlloc(a types.GenesisAlloc) sutOption {
164+
return options.Func[sutConfig](func(c *sutConfig) {
165+
c.extraAlloc = a
166+
})
167+
}
168+
160169
func TestImmediateShutdownNonBlocking(t *testing.T) {
161170
newSUT(t) // calls [Executor.Close] in test cleanup
162171
}
@@ -1054,3 +1063,94 @@ func TestArchivalStoresAll(t *testing.T) {
10541063
}
10551064
})
10561065
}
1066+
1067+
// TestProcessBeaconBlockRoot verifies that block execution performs the
1068+
// EIP-4788 system call.
1069+
//
1070+
// The contract is deployed according to the EIP, which lands the contract at
1071+
// [params.BeaconRootsStorageAddress]. A later block then carries a parent
1072+
// beacon root, and we assert on the contract's observable behaviour by querying
1073+
// it for that block's timestamp.
1074+
func TestProcessBeaconBlockRoot(t *testing.T) {
1075+
beaconRoot := common.HexToHash("0xbeef")
1076+
1077+
// This is the canonical EIP-4788 deployment transaction from
1078+
// https://eips.ethereum.org/EIPS/eip-4788#deployment.
1079+
deployer := common.HexToAddress("0x0B799C86a49DEeb90402691F1041aa3AF2d3C875")
1080+
deployTx := types.NewTx(&types.LegacyTx{
1081+
Nonce: 0,
1082+
GasPrice: big.NewInt(0xe8d4a51000),
1083+
Gas: 0x3d090,
1084+
Data: common.FromHex("0x60618060095f395ff33373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500"),
1085+
V: big.NewInt(0x1b),
1086+
R: big.NewInt(0x539),
1087+
S: big.NewInt(0x1b9b6eb1f0),
1088+
})
1089+
1090+
{ // test setup validation
1091+
require.Equal(t, common.HexToHash("0xdf52c2d3bbe38820fff7b5eaab3db1b91f8e1412b56497d88388fb5d4ea1fde0"), deployTx.Hash(), "deployment tx hash matches EIP")
1092+
sender, err := types.Sender(types.LatestSigner(saetest.ChainConfig()), deployTx)
1093+
require.NoError(t, err, "types.Sender([deployment tx])")
1094+
require.Equal(t, deployer, sender, "types.Sender([deployment tx])")
1095+
}
1096+
1097+
tests := []struct {
1098+
name string
1099+
beaconRoot *common.Hash
1100+
want []byte
1101+
wantErr testerr.Want
1102+
}{
1103+
{
1104+
name: "stores parent beacon root, queryable via beacon-roots contract",
1105+
beaconRoot: &beaconRoot,
1106+
want: beaconRoot[:],
1107+
wantErr: nil,
1108+
},
1109+
{
1110+
name: "nil parent beacon root: nothing stored, query reverts",
1111+
beaconRoot: nil,
1112+
want: nil,
1113+
wantErr: testerr.Is(vm.ErrExecutionReverted),
1114+
},
1115+
}
1116+
for _, tt := range tests {
1117+
t.Run(tt.name, func(t *testing.T) {
1118+
// Fund only the keyless deployer EOA; the contract itself is deployed
1119+
// by the transaction, not pre-allocated.
1120+
ctx, sut := newSUT(t, withExtraAlloc(types.GenesisAlloc{
1121+
deployer: {Balance: big.NewInt(math.MaxInt64)},
1122+
}))
1123+
e := sut.Executor
1124+
1125+
deployBlock := sut.chain.NewBlock(t, types.Transactions{deployTx})
1126+
require.NoError(t, e.Enqueue(ctx, deployBlock), "Enqueue(deployment)")
1127+
1128+
b := sut.chain.NewBlock(t, nil, blockstest.WithEthBlockOptions(
1129+
blockstest.ModifyHeader(func(h *types.Header) {
1130+
h.Time = 1 // non-zero timestamp is required
1131+
h.ParentBeaconRoot = tt.beaconRoot
1132+
}),
1133+
))
1134+
require.NoError(t, e.Enqueue(ctx, b), "Enqueue(beacon)")
1135+
require.NoErrorf(t, b.WaitUntilExecuted(ctx), "%T.WaitUntilExecuted()", b)
1136+
1137+
sdb, err := e.StateDB(b.PostExecutionStateRoot())
1138+
require.NoErrorf(t, err, "%T.StateDB(%T.PostExecutionStateRoot())", e, b)
1139+
1140+
header := b.Header()
1141+
blockCtx := core.NewEVMBlockContext(header, nil /*chain; unused by get()*/, &header.Coinbase)
1142+
evm := vm.NewEVM(blockCtx, vm.TxContext{}, sdb, saetest.ChainConfig(), vm.Config{})
1143+
1144+
got, _, err := evm.StaticCall(
1145+
vm.AccountRef(common.Address{}),
1146+
params.BeaconRootsStorageAddress,
1147+
uint256.NewInt(header.Time).PaddedBytes(32),
1148+
1e6,
1149+
)
1150+
if diff := testerr.Diff(err, tt.wantErr); diff != "" {
1151+
t.Errorf("beacon-roots get() via StaticCall() %s", diff)
1152+
}
1153+
assert.Equal(t, tt.want, got, "parent beacon root returned by beacon-roots contract")
1154+
})
1155+
}
1156+
}

0 commit comments

Comments
 (0)