Commit 8acece49 authored by Mark Tyneway's avatar Mark Tyneway Committed by Matthew Slipper

op-chain-ops: add bedrock transition receipts

To make withdrawals really easy, we need to add in
receipts corresponding to the migrated withdrawals.
This will allow the exact same flow to be used when
creating the withdrawing transactions as normal
withdrawals.
parent 1366092e
......@@ -6,6 +6,7 @@ import (
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
......@@ -126,3 +127,37 @@ func (w *LegacyWithdrawal) StorageSlot() (common.Hash, error) {
slot := crypto.Keccak256(preimage)
return common.BytesToHash(slot), nil
}
// Value returns the ETH value associated with the withdrawal.
func (w *LegacyWithdrawal) Value() (*big.Int, error) {
abi, err := bindings.L1StandardBridgeMetaData.GetAbi()
if err != nil {
return nil, err
}
method, err := abi.MethodById(w.Data)
if err != nil {
return nil, err
}
value := new(big.Int)
isFromL2StandardBridge := *w.Sender == predeploys.L2StandardBridgeAddr
if isFromL2StandardBridge && method.Name == "finalizeETHWithdrawal" {
data, err := method.Inputs.Unpack(w.Data[4:])
if err != nil {
return nil, err
}
// bounds check
if len(data) < 3 {
return nil, errors.New("not enough data")
}
var ok bool
value, ok = data[2].(*big.Int)
if !ok {
return nil, errors.New("not big.Int")
}
}
return value, nil
}
......@@ -10,6 +10,7 @@ var (
Uint256Type, _ = abi.NewType("uint256", "", nil)
BytesType, _ = abi.NewType("bytes", "", nil)
AddressType, _ = abi.NewType("address", "", nil)
Bytes32Type, _ = abi.NewType("bytes32", "", nil)
)
// WithdrawalMessage represents a Withdrawal. The Withdrawal
......
......@@ -4,11 +4,22 @@ import (
"errors"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
)
var (
SentMessageEventABI = "SentMessage(address,address,bytes,uint256)"
SentMessageEventABIHash = crypto.Keccak256Hash([]byte(SentMessageEventABI))
SentMessageExtension1EventABI = "SentMessage(address,uint256)"
SentMessageExtension1EventABIHash = crypto.Keccak256Hash([]byte(SentMessageExtension1EventABI))
MessagePassedEventABI = "MessagePassed(uint256,address,address,uint256,uint256,bytes,bytes32)"
MessagePassedEventABIHash = crypto.Keccak256Hash([]byte(MessagePassedEventABI))
)
var _ WithdrawalMessage = (*Withdrawal)(nil)
// Withdrawal represents a withdrawal transaction on L2
......@@ -130,3 +141,98 @@ func (w *Withdrawal) StorageSlot() (common.Hash, error) {
slot := crypto.Keccak256(preimage)
return common.BytesToHash(slot), nil
}
// Compute the receipt corresponding to the withdrawal. This receipt
// is in the bedrock transition block. It contains 3 logs
// - SentMessage
// - SentMessageExtension1
// - MessagePassed
// These logs are enough for the standard withdrawal flow to happen
// which is driven by events being emitted.
func (w *Withdrawal) Receipt(hdr *types.Header) (*types.Receipt, error) {
receipt := types.NewReceipt(hdr.Root.Bytes(), false, 0)
args := abi.Arguments{
{Name: "target", Type: AddressType},
{Name: "sender", Type: AddressType},
{Name: "data", Type: BytesType},
{Name: "nonce", Type: Uint256Type},
}
data, err := args.Pack(w.Target, w.Sender, w.Data, w.Nonce)
if err != nil {
return nil, err
}
sm := &types.Log{
Address: predeploys.L2CrossDomainMessengerAddr,
Topics: []common.Hash{
SentMessageEventABIHash,
w.Target.Hash(),
},
Data: data,
BlockNumber: hdr.Number.Uint64(),
TxHash: common.Hash{},
TxIndex: 0,
BlockHash: hdr.Hash(),
Index: 0,
Removed: false,
}
receipt.Logs = append(receipt.Logs, sm)
sm1 := &types.Log{
Address: predeploys.L2CrossDomainMessengerAddr,
Topics: []common.Hash{
SentMessageExtension1EventABIHash,
w.Sender.Hash(),
},
Data: common.LeftPadBytes(w.Value.Bytes(), 32),
BlockNumber: hdr.Number.Uint64(),
TxHash: common.Hash{},
TxIndex: 0,
BlockHash: hdr.Hash(),
Index: 0,
Removed: false,
}
receipt.Logs = append(receipt.Logs, sm1)
mpargs := abi.Arguments{
{Name: "value", Type: Uint256Type},
{Name: "gasLimit", Type: Uint256Type},
{Name: "data", Type: BytesType},
{Name: "withdrawalHash", Type: Bytes32Type},
}
hash, err := w.Hash()
if err != nil {
return nil, err
}
mpdata, err := mpargs.Pack(w.Value, w.GasLimit, w.Data, hash)
if err != nil {
return nil, err
}
mp := &types.Log{
Address: predeploys.L2ToL1MessagePasserAddr,
Topics: []common.Hash{
MessagePassedEventABIHash,
common.BytesToHash(common.LeftPadBytes(w.Nonce.Bytes(), 32)),
w.Sender.Hash(),
w.Target.Hash(),
},
Data: mpdata,
BlockNumber: hdr.Number.Uint64(),
TxHash: common.Hash{},
TxIndex: 0,
BlockHash: hdr.Hash(),
Index: 0,
Removed: false,
}
receipt.Logs = append(receipt.Logs, mp)
return receipt, nil
}
......@@ -115,7 +115,12 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
BaseFee: (*big.Int)(config.L2GenesisBlockBaseFeePerGas),
}
bedrockBlock := types.NewBlock(bedrockHeader, nil, nil, nil, trie.NewStackTrie(nil))
receipts, err := CreateReceipts(bedrockHeader, withdrawals, &config.L1CrossDomainMessengerProxy, &config.L1StandardBridgeProxy)
if err != nil {
return nil, err
}
bedrockBlock := types.NewBlock(bedrockHeader, nil, nil, receipts, trie.NewStackTrie(nil))
res := &MigrationResult{
TransitionHeight: bedrockBlock.NumberU64(),
......@@ -130,7 +135,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
rawdb.WriteTd(ldb, bedrockBlock.Hash(), bedrockBlock.NumberU64(), bedrockBlock.Difficulty())
rawdb.WriteBlock(ldb, bedrockBlock)
rawdb.WriteReceipts(ldb, bedrockBlock.Hash(), bedrockBlock.NumberU64(), nil)
rawdb.WriteReceipts(ldb, bedrockBlock.Hash(), bedrockBlock.NumberU64(), receipts)
rawdb.WriteCanonicalHash(ldb, bedrockBlock.Hash(), bedrockBlock.NumberU64())
rawdb.WriteHeadBlockHash(ldb, bedrockBlock.Hash())
rawdb.WriteHeadFastBlockHash(ldb, bedrockBlock.Hash())
......
package genesis
import (
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// CreateReceipts will create the set of bedrock genesis receipts given
// a list of legacy withdrawals.
func CreateReceipts(
hdr *types.Header,
withdrawals []*crossdomain.LegacyWithdrawal,
l1CrossDomainMessenger, l1StandardBridge *common.Address,
) ([]*types.Receipt, error) {
receipts := make([]*types.Receipt, 0)
for _, withdrawal := range withdrawals {
wd, err := crossdomain.MigrateWithdrawal(withdrawal, l1CrossDomainMessenger, l1StandardBridge)
if err != nil {
return nil, err
}
receipt, err := wd.Receipt(hdr)
if err != nil {
return nil, err
}
receipts = append(receipts, receipt)
}
return receipts, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment