core, params, beacon/engine: implement EIP 4788 BeaconRoot (#27849)

This change implements "EIP 4788 : Beacon block root in the EVM". It implements version-2 of EPI-4788, main difference being that the contract is an actual contract rather than a precompile, as in #27289.
This commit is contained in:
Martin Holst Swende
2023-08-22 08:33:39 -04:00
committed by GitHub
parent 0b4b299099
commit b8d38e76ef
19 changed files with 436 additions and 187 deletions
+3
View File
@@ -487,6 +487,9 @@ func (g *Genesis) ToBlock() *types.Block {
if head.BlobGasUsed == nil {
head.BlobGasUsed = new(uint64)
}
if head.BeaconRoot == nil {
head.BeaconRoot = new(common.Hash)
}
}
}
return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)).WithWithdrawals(withdrawals)
+23
View File
@@ -76,6 +76,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
signer = types.MakeSigner(p.config, header.Number, header.Time)
)
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
}
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() {
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
@@ -160,3 +163,23 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
vmenv := vm.NewEVM(blockContext, vm.TxContext{BlobHashes: tx.BlobHashes()}, statedb, config, cfg)
return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
}
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
// contract. This method is exported to be used in tests.
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
// the new root
msg := &Message{
From: params.SystemAddress,
GasLimit: 30_000_000,
GasPrice: common.Big0,
GasFeeCap: common.Big0,
GasTipCap: common.Big0,
To: &params.BeaconRootsStorageAddress,
Data: beaconRoot[:],
}
vmenv.Reset(NewEVMTxContext(msg), statedb)
statedb.AddAddressToAccessList(params.BeaconRootsStorageAddress)
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.Big0)
statedb.Finalise(true)
}
+3
View File
@@ -410,6 +410,9 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
used := uint64(nBlobs * params.BlobTxBlobGasPerBlob)
header.ExcessBlobGas = &excess
header.BlobGasUsed = &used
beaconRoot := common.HexToHash("0xbeac00")
header.BeaconRoot = &beaconRoot
}
// Assemble and return the final block for sealing
if config.IsShanghai(header.Number, header.Time) {
+9
View File
@@ -90,6 +90,9 @@ type Header struct {
// ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers.
ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`
// BeaconRoot was added by EIP-4788 and is ignored in legacy headers.
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
}
// field type overrides for gencodec
@@ -297,6 +300,10 @@ func CopyHeader(h *Header) *Header {
cpy.BlobGasUsed = new(uint64)
*cpy.BlobGasUsed = *h.BlobGasUsed
}
if h.BeaconRoot != nil {
cpy.BeaconRoot = new(common.Hash)
*cpy.BeaconRoot = *h.BeaconRoot
}
return &cpy
}
@@ -376,6 +383,8 @@ func (b *Block) BaseFee() *big.Int {
return new(big.Int).Set(b.header.BaseFee)
}
func (b *Block) BeaconRoot() *common.Hash { return b.header.BeaconRoot }
func (b *Block) ExcessBlobGas() *uint64 {
var excessBlobGas *uint64
if b.header.ExcessBlobGas != nil {
+6
View File
@@ -35,6 +35,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
Hash common.Hash `json:"hash"`
}
var enc Header
@@ -57,6 +58,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
enc.WithdrawalsHash = h.WithdrawalsHash
enc.BlobGasUsed = (*hexutil.Uint64)(h.BlobGasUsed)
enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas)
enc.BeaconRoot = h.BeaconRoot
enc.Hash = h.Hash()
return json.Marshal(&enc)
}
@@ -83,6 +85,7 @@ func (h *Header) UnmarshalJSON(input []byte) error {
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
}
var dec Header
if err := json.Unmarshal(input, &dec); err != nil {
@@ -157,5 +160,8 @@ func (h *Header) UnmarshalJSON(input []byte) error {
if dec.ExcessBlobGas != nil {
h.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
}
if dec.BeaconRoot != nil {
h.BeaconRoot = dec.BeaconRoot
}
return nil
}
+12 -4
View File
@@ -44,7 +44,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
_tmp2 := obj.WithdrawalsHash != nil
_tmp3 := obj.BlobGasUsed != nil
_tmp4 := obj.ExcessBlobGas != nil
if _tmp1 || _tmp2 || _tmp3 || _tmp4 {
_tmp5 := obj.BeaconRoot != nil
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 {
if obj.BaseFee == nil {
w.Write(rlp.EmptyString)
} else {
@@ -54,27 +55,34 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
w.WriteBigInt(obj.BaseFee)
}
}
if _tmp2 || _tmp3 || _tmp4 {
if _tmp2 || _tmp3 || _tmp4 || _tmp5 {
if obj.WithdrawalsHash == nil {
w.Write([]byte{0x80})
} else {
w.WriteBytes(obj.WithdrawalsHash[:])
}
}
if _tmp3 || _tmp4 {
if _tmp3 || _tmp4 || _tmp5 {
if obj.BlobGasUsed == nil {
w.Write([]byte{0x80})
} else {
w.WriteUint64((*obj.BlobGasUsed))
}
}
if _tmp4 {
if _tmp4 || _tmp5 {
if obj.ExcessBlobGas == nil {
w.Write([]byte{0x80})
} else {
w.WriteUint64((*obj.ExcessBlobGas))
}
}
if _tmp5 {
if obj.BeaconRoot == nil {
w.Write([]byte{0x80})
} else {
w.WriteBytes(obj.BeaconRoot[:])
}
}
w.ListEnd(_tmp0)
return w.Flush()
}