Commit 0a99aaac authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #1356 from ethereum-optimism/develop

merge develop into master
parents b9a47cbc 4425e9f5
---
'@eth-optimism/l2geth': patch
---
Reduce the geth diff
...@@ -123,6 +123,12 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { ...@@ -123,6 +123,12 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
return err return err
} }
abi.Methods = make(map[string]Method) abi.Methods = make(map[string]Method)
// UsingOVM specific changes
// Create a cache of methods when running under the OVM because
// looking up methods based on the 4 byte selector is part of the hot
// code path. Without this cache, it was observed that 50% of the CPU
// time during syncing was spent hashing the function selectors
// during the call to `abi.MethodsById`
abi.MethodsById = make(map[[4]byte]*Method) abi.MethodsById = make(map[[4]byte]*Method)
abi.Events = make(map[string]Event) abi.Events = make(map[string]Event)
for _, field := range fields { for _, field := range fields {
...@@ -148,7 +154,8 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { ...@@ -148,7 +154,8 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
Outputs: field.Outputs, Outputs: field.Outputs,
} }
abi.Methods[name] = method abi.Methods[name] = method
// add method to the id cache // UsingOVM specific changes
// Add method to the id cache
sigdata := method.ID() sigdata := method.ID()
abi.MethodsById[[4]byte{sigdata[0], sigdata[1], sigdata[2], sigdata[3]}] = &method abi.MethodsById[[4]byte{sigdata[0], sigdata[1], sigdata[2], sigdata[3]}] = &method
case "event": case "event":
...@@ -177,6 +184,9 @@ func (abi *ABI) MethodById(sigdata []byte) (*Method, error) { ...@@ -177,6 +184,9 @@ func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata)) return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata))
} }
// UsingOVM specific changes
// Use the method cache to prevent the need to iterate and hash
// each method in the ABI
method, exist := abi.MethodsById[[4]byte{sigdata[0], sigdata[1], sigdata[2], sigdata[3]}] method, exist := abi.MethodsById[[4]byte{sigdata[0], sigdata[1], sigdata[2], sigdata[3]}]
if !exist { if !exist {
return nil, fmt.Errorf("no method with id: %#x", sigdata[:4]) return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
...@@ -195,6 +205,11 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) { ...@@ -195,6 +205,11 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) {
return nil, fmt.Errorf("no event with id: %#x", topic.Hex()) return nil, fmt.Errorf("no event with id: %#x", topic.Hex())
} }
// UsingOVM
// Both RevertSelector and UnpackRevert were pulled from upstream
// geth as they were not present in the version of geth that this
// codebase was forked from. These are useful for displaying revert
// messages to users when they use `eth_call`
// RevertSelector is a special function selector for revert reason unpacking. // RevertSelector is a special function selector for revert reason unpacking.
var RevertSelector = crypto.Keccak256([]byte("Error(string)"))[:4] var RevertSelector = crypto.Keccak256([]byte("Error(string)"))[:4]
......
...@@ -601,6 +601,8 @@ func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } ...@@ -601,6 +601,8 @@ func (m callmsg) Gas() uint64 { return m.CallMsg.Gas }
func (m callmsg) Value() *big.Int { return m.CallMsg.Value } func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
func (m callmsg) Data() []byte { return m.CallMsg.Data } func (m callmsg) Data() []byte { return m.CallMsg.Data }
// UsingOVM
// These getters return OVM specific fields
func (m callmsg) L1MessageSender() *common.Address { return m.CallMsg.L1MessageSender } func (m callmsg) L1MessageSender() *common.Address { return m.CallMsg.L1MessageSender }
func (m callmsg) L1BlockNumber() *big.Int { return m.CallMsg.L1BlockNumber } func (m callmsg) L1BlockNumber() *big.Int { return m.CallMsg.L1BlockNumber }
func (m callmsg) QueueOrigin() types.QueueOrigin { return m.CallMsg.QueueOrigin } func (m callmsg) QueueOrigin() types.QueueOrigin { return m.CallMsg.QueueOrigin }
......
...@@ -85,7 +85,10 @@ func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore { ...@@ -85,7 +85,10 @@ func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore {
ks.init(keydir) ks.init(keydir)
if vm.UsingOVM { if vm.UsingOVM {
// Add a deterministic key to the key store so that // Add a deterministic key to the key store so that
// all clique blocks are signed with the same key // all clique blocks are signed with the same key.
// This change will result in deterministic blocks across
// the entire network. This change is necessary due to
// each node running its own single signer clique consensus.
input := make([]byte, 65) input := make([]byte, 65)
rng := bytes.NewReader(input) rng := bytes.NewReader(input)
key, err := newKey(rng) key, err := newKey(rng)
......
...@@ -149,6 +149,9 @@ var ( ...@@ -149,6 +149,9 @@ var (
configFileFlag, configFileFlag,
} }
// UsingOVM
// Optimism specific flags must be added to the application
// flag parsing logic
optimismFlags = []cli.Flag{ optimismFlags = []cli.Flag{
utils.Eth1SyncServiceEnable, utils.Eth1SyncServiceEnable,
utils.Eth1CanonicalTransactionChainDeployHeightFlag, utils.Eth1CanonicalTransactionChainDeployHeightFlag,
...@@ -248,6 +251,7 @@ func init() { ...@@ -248,6 +251,7 @@ func init() {
sort.Sort(cli.CommandsByName(app.Commands)) sort.Sort(cli.CommandsByName(app.Commands))
app.Flags = append(app.Flags, nodeFlags...) app.Flags = append(app.Flags, nodeFlags...)
// UsingOVM
app.Flags = append(app.Flags, optimismFlags...) app.Flags = append(app.Flags, optimismFlags...)
app.Flags = append(app.Flags, rpcFlags...) app.Flags = append(app.Flags, rpcFlags...)
app.Flags = append(app.Flags, consoleFlags...) app.Flags = append(app.Flags, consoleFlags...)
...@@ -454,6 +458,11 @@ func startNode(ctx *cli.Context, stack *node.Node) { ...@@ -454,6 +458,11 @@ func startNode(ctx *cli.Context, stack *node.Node) {
if err := ethereum.StartMining(threads); err != nil { if err := ethereum.StartMining(threads); err != nil {
utils.Fatalf("Failed to start mining: %v", err) utils.Fatalf("Failed to start mining: %v", err)
} }
// UsingOVM
// Can optionally configure the sync service. Turning it off allows
// for statically serving historical data and is also useful for
// local development. When it is turned on, it will attempt to sync
// using the `RollupClient`
if ctx.GlobalBool(utils.Eth1SyncServiceEnable.Name) { if ctx.GlobalBool(utils.Eth1SyncServiceEnable.Name) {
if err := ethereum.SyncService().Start(); err != nil { if err := ethereum.SyncService().Start(); err != nil {
utils.Fatalf("Failed to start syncservice: %v", err) utils.Fatalf("Failed to start syncservice: %v", err)
......
...@@ -63,6 +63,7 @@ type flagGroup struct { ...@@ -63,6 +63,7 @@ type flagGroup struct {
// AppHelpFlagGroups is the application flags, grouped by functionality. // AppHelpFlagGroups is the application flags, grouped by functionality.
var AppHelpFlagGroups = []flagGroup{ var AppHelpFlagGroups = []flagGroup{
{ {
// UsingOVM
Name: "OPTIMISM", Name: "OPTIMISM",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.Eth1SyncServiceEnable, utils.Eth1SyncServiceEnable,
......
...@@ -1130,6 +1130,7 @@ func setIPC(ctx *cli.Context, cfg *node.Config) { ...@@ -1130,6 +1130,7 @@ func setIPC(ctx *cli.Context, cfg *node.Config) {
} }
} }
// UsingOVM
// setEth1 configures the sync service // setEth1 configures the sync service
func setEth1(ctx *cli.Context, cfg *rollup.Config) { func setEth1(ctx *cli.Context, cfg *rollup.Config) {
if ctx.GlobalIsSet(Eth1CanonicalTransactionChainDeployHeightFlag.Name) { if ctx.GlobalIsSet(Eth1CanonicalTransactionChainDeployHeightFlag.Name) {
...@@ -1159,6 +1160,8 @@ func setEth1(ctx *cli.Context, cfg *rollup.Config) { ...@@ -1159,6 +1160,8 @@ func setEth1(ctx *cli.Context, cfg *rollup.Config) {
} }
} }
// UsingOVM
// setRollup configures the rollup
func setRollup(ctx *cli.Context, cfg *rollup.Config) { func setRollup(ctx *cli.Context, cfg *rollup.Config) {
if ctx.GlobalIsSet(RollupAddressManagerOwnerAddressFlag.Name) { if ctx.GlobalIsSet(RollupAddressManagerOwnerAddressFlag.Name) {
addr := ctx.GlobalString(RollupAddressManagerOwnerAddressFlag.Name) addr := ctx.GlobalString(RollupAddressManagerOwnerAddressFlag.Name)
...@@ -1764,6 +1767,10 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { ...@@ -1764,6 +1767,10 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
chainID = new(big.Int).SetUint64(id) chainID = new(big.Int).SetUint64(id)
} }
// UsingOVM
// The genesis block includes state that is set at runtime.
// This allows the statedump to be generic and not created
// specific for each network.
gasLimit := cfg.Rollup.GasLimit gasLimit := cfg.Rollup.GasLimit
if gasLimit == 0 { if gasLimit == 0 {
gasLimit = params.GenesisGasLimit gasLimit = params.GenesisGasLimit
......
...@@ -324,10 +324,16 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type ...@@ -324,10 +324,16 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type
if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
return consensus.ErrUnknownAncestor return consensus.ErrUnknownAncestor
} }
// [REMOVED] to account for timestamp changes
//if parent.Time+c.config.Period > header.Time { // Do not account for timestamps in consensus when running the OVM
// return ErrInvalidTimestamp // changes. The timestamp must be montonic, meaning that it can be the same
//} // or increase. L1 dictates the timestamp.
if !vm.UsingOVM {
if parent.Time+c.config.Period > header.Time {
return ErrInvalidTimestamp
}
}
// Retrieve the snapshot needed to verify this header and cache it // Retrieve the snapshot needed to verify this header and cache it
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents) snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
if err != nil { if err != nil {
...@@ -547,11 +553,14 @@ func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) erro ...@@ -547,11 +553,14 @@ func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) erro
if parent == nil { if parent == nil {
return consensus.ErrUnknownAncestor return consensus.ErrUnknownAncestor
} }
// [REMOVED] so we can control timestamps
//header.Time = parent.Time + c.config.Period // Do not manipulate the timestamps when running with the OVM
//if header.Time < uint64(time.Now().Unix()) { if !vm.UsingOVM {
// header.Time = uint64(time.Now().Unix()) header.Time = parent.Time + c.config.Period
//} if header.Time < uint64(time.Now().Unix()) {
header.Time = uint64(time.Now().Unix())
}
}
return nil return nil
} }
......
...@@ -254,7 +254,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent * ...@@ -254,7 +254,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
return consensus.ErrFutureBlock return consensus.ErrFutureBlock
} }
} }
if header.Time < parent.Time { if header.Time <= parent.Time {
return errOlderBlockTime return errOlderBlockTime
} }
// Verify the block's difficulty based on its timestamp and parent's difficulty // Verify the block's difficulty based on its timestamp and parent's difficulty
...@@ -273,18 +273,16 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent * ...@@ -273,18 +273,16 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
} }
// TODO: UNCOMMENT THIS CHECK WHEN WE UNDERSTAND OUR GAS LIMIT REQUIREMENTS
// Verify that the gas limit remains within allowed bounds // Verify that the gas limit remains within allowed bounds
//diff := int64(parent.GasLimit) - int64(header.GasLimit) diff := int64(parent.GasLimit) - int64(header.GasLimit)
//if diff < 0 { if diff < 0 {
// diff *= -1 diff *= -1
//} }
//limit := parent.GasLimit / params.GasLimitBoundDivisor limit := parent.GasLimit / params.GasLimitBoundDivisor
//if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit {
// return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit)
//} }
// Verify that the block number is parent's +1 // Verify that the block number is parent's +1
if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
......
...@@ -816,6 +816,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { ...@@ -816,6 +816,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
// Tests that chain reorganisations handle transaction removals and reinsertions. // Tests that chain reorganisations handle transaction removals and reinsertions.
func TestChainTxReorgs(t *testing.T) { func TestChainTxReorgs(t *testing.T) {
t.Skip("UsingOVM")
var ( var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
......
...@@ -29,9 +29,6 @@ import ( ...@@ -29,9 +29,6 @@ import (
) )
func ExampleGenerateChain() { func ExampleGenerateChain() {
fmt.Println("OVM breaks this... SKIPPING: Example Generate Chain fails because of the genesis.")
return
var ( var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
...@@ -95,9 +92,9 @@ func ExampleGenerateChain() { ...@@ -95,9 +92,9 @@ func ExampleGenerateChain() {
fmt.Println("balance of addr1:", state.GetBalance(addr1)) fmt.Println("balance of addr1:", state.GetBalance(addr1))
fmt.Println("balance of addr2:", state.GetBalance(addr2)) fmt.Println("balance of addr2:", state.GetBalance(addr2))
fmt.Println("balance of addr3:", state.GetBalance(addr3)) fmt.Println("balance of addr3:", state.GetBalance(addr3))
// // Output: // Output:
// // last block: #5 // last block: #5
// // balance of addr1: 989000 // balance of addr1: 989000
// // balance of addr2: 10000 // balance of addr2: 10000
// // balance of addr3: 19687500000000001000 // balance of addr3: 19687500000000001000
} }
...@@ -267,7 +267,12 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { ...@@ -267,7 +267,12 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
} }
} }
// ApplyOvmStateToState applies the initial OVM state to a state object. // UsingOVM
// ApplyOvmStateToState applies the initial OVM state to a statedb.
// It inserts a bunch of runtime config into the state.
// It is fragile to storage slots changing as it directly writes to storage
// slots instead of applying messages with well formed calldata.
// This function could be replaced in the future using GenesisAlloc
func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDomainMessengerAddress, l1StandardBridgeAddress, addrManagerOwnerAddress, gpoOwnerAddress, l1FeeWalletAddress common.Address, chainID *big.Int, gasLimit uint64) { func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDomainMessengerAddress, l1StandardBridgeAddress, addrManagerOwnerAddress, gpoOwnerAddress, l1FeeWalletAddress common.Address, chainID *big.Int, gasLimit uint64) {
if len(stateDump.Accounts) == 0 { if len(stateDump.Accounts) == 0 {
return return
...@@ -475,7 +480,11 @@ func DefaultGoerliGenesisBlock() *Genesis { ...@@ -475,7 +480,11 @@ func DefaultGoerliGenesisBlock() *Genesis {
} }
} }
// UsingOVM
// DeveloperGenesisBlock returns the 'geth --dev' genesis block. // DeveloperGenesisBlock returns the 'geth --dev' genesis block.
// Additional runtime parameters are passed through that impact
// the genesis state. An "incompatible genesis block" error means that
// these params were altered since the initial creation of the datadir.
func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress common.Address, l1StandardBridgeAddress common.Address, addrManagerOwnerAddress, gpoOwnerAddress, l1FeeWalletAddress common.Address, stateDumpPath string, chainID *big.Int, gasLimit uint64) *Genesis { func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress common.Address, l1StandardBridgeAddress common.Address, addrManagerOwnerAddress, gpoOwnerAddress, l1FeeWalletAddress common.Address, stateDumpPath string, chainID *big.Int, gasLimit uint64) *Genesis {
// Override the default period to the user requested one // Override the default period to the user requested one
config := *params.AllCliqueProtocolChanges config := *params.AllCliqueProtocolChanges
...@@ -488,6 +497,10 @@ func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress comm ...@@ -488,6 +497,10 @@ func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress comm
stateDump := dump.OvmDump{} stateDump := dump.OvmDump{}
if vm.UsingOVM { if vm.UsingOVM {
// Fetch the state dump from the state dump path // Fetch the state dump from the state dump path
// The system cannot start without a state dump as it depends on
// the ABIs that are included in the state dump. Check that all
// required state dump entries are present to prevent a faulty
// state dump from being used
if stateDumpPath == "" { if stateDumpPath == "" {
panic("Must pass state dump path") panic("Must pass state dump path")
} }
...@@ -531,6 +544,9 @@ func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress comm ...@@ -531,6 +544,9 @@ func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress comm
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
}, },
// UsingOVM
// Add additional properties to the genesis block so that they can
// be added into the initial genesis state at runtime
L1CrossDomainMessengerAddress: l1XDomainMessengerAddress, L1CrossDomainMessengerAddress: l1XDomainMessengerAddress,
L1FeeWalletAddress: l1FeeWalletAddress, L1FeeWalletAddress: l1FeeWalletAddress,
AddressManagerOwnerAddress: addrManagerOwnerAddress, AddressManagerOwnerAddress: addrManagerOwnerAddress,
...@@ -552,6 +568,10 @@ func decodePrealloc(data string) GenesisAlloc { ...@@ -552,6 +568,10 @@ func decodePrealloc(data string) GenesisAlloc {
return ga return ga
} }
// UsingOVM
// fetchStateDump will fetch a state dump from a remote HTTP endpoint.
// This state dump includes the OVM system contracts as well as previous
// user state if the network has previously had a regenesis.
func fetchStateDump(path string, stateDump *dump.OvmDump) error { func fetchStateDump(path string, stateDump *dump.OvmDump) error {
if stateDump == nil { if stateDump == nil {
return errors.New("Unable to fetch state dump") return errors.New("Unable to fetch state dump")
......
...@@ -338,6 +338,7 @@ func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { ...@@ -338,6 +338,7 @@ func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
} }
} }
// UsingOVM
// ReadTransactionMeta returns the transaction metadata associated with a // ReadTransactionMeta returns the transaction metadata associated with a
// transaction hash. // transaction hash.
func ReadTransactionMeta(db ethdb.Reader, number uint64) *types.TransactionMeta { func ReadTransactionMeta(db ethdb.Reader, number uint64) *types.TransactionMeta {
...@@ -355,6 +356,7 @@ func ReadTransactionMeta(db ethdb.Reader, number uint64) *types.TransactionMeta ...@@ -355,6 +356,7 @@ func ReadTransactionMeta(db ethdb.Reader, number uint64) *types.TransactionMeta
return meta return meta
} }
// UsingOVM
// ReadTransactionMetaRaw returns the raw transaction metadata associated with a // ReadTransactionMetaRaw returns the raw transaction metadata associated with a
// transaction hash. // transaction hash.
func ReadTransactionMetaRaw(db ethdb.Reader, number uint64) []byte { func ReadTransactionMetaRaw(db ethdb.Reader, number uint64) []byte {
...@@ -365,12 +367,14 @@ func ReadTransactionMetaRaw(db ethdb.Reader, number uint64) []byte { ...@@ -365,12 +367,14 @@ func ReadTransactionMetaRaw(db ethdb.Reader, number uint64) []byte {
return nil return nil
} }
// UsingOVM
// WriteTransactionMeta writes the TransactionMeta to disk by hash. // WriteTransactionMeta writes the TransactionMeta to disk by hash.
func WriteTransactionMeta(db ethdb.KeyValueWriter, number uint64, meta *types.TransactionMeta) { func WriteTransactionMeta(db ethdb.KeyValueWriter, number uint64, meta *types.TransactionMeta) {
data := types.TxMetaEncode(meta) data := types.TxMetaEncode(meta)
WriteTransactionMetaRaw(db, number, data) WriteTransactionMetaRaw(db, number, data)
} }
// UsingOVM
// WriteTransactionMetaRaw writes the raw transaction metadata bytes to disk. // WriteTransactionMetaRaw writes the raw transaction metadata bytes to disk.
func WriteTransactionMetaRaw(db ethdb.KeyValueWriter, number uint64, data []byte) { func WriteTransactionMetaRaw(db ethdb.KeyValueWriter, number uint64, data []byte) {
if err := db.Put(txMetaKey(number), data); err != nil { if err := db.Put(txMetaKey(number), data); err != nil {
...@@ -378,6 +382,7 @@ func WriteTransactionMetaRaw(db ethdb.KeyValueWriter, number uint64, data []byte ...@@ -378,6 +382,7 @@ func WriteTransactionMetaRaw(db ethdb.KeyValueWriter, number uint64, data []byte
} }
} }
// UsingOVM
// DeleteTransactionMeta removes the transaction metadata associated with a hash // DeleteTransactionMeta removes the transaction metadata associated with a hash
func DeleteTransactionMeta(db ethdb.KeyValueWriter, number uint64) { func DeleteTransactionMeta(db ethdb.KeyValueWriter, number uint64) {
if err := db.Delete(txMetaKey(number)); err != nil { if err := db.Delete(txMetaKey(number)); err != nil {
...@@ -577,6 +582,11 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { ...@@ -577,6 +582,11 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block {
if body == nil { if body == nil {
return nil return nil
} }
// UsingOVM
// Read all of the transaction meta from the db when reading a block
// and set the txmeta on each transaction. This is because the tx meta
// is not included as part of the RLP encoding of a transaction to be
// backwards compatible with layer one
for i := 0; i < len(body.Transactions); i++ { for i := 0; i < len(body.Transactions); i++ {
meta := ReadTransactionMeta(db, header.Number.Uint64()) meta := ReadTransactionMeta(db, header.Number.Uint64())
body.Transactions[i].SetTransactionMeta(meta) body.Transactions[i].SetTransactionMeta(meta)
......
...@@ -86,6 +86,10 @@ func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, com ...@@ -86,6 +86,10 @@ func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, com
} }
for txIndex, tx := range body.Transactions { for txIndex, tx := range body.Transactions {
if tx.Hash() == hash { if tx.Hash() == hash {
// UsingOVM
// Read the transaction meta from the database and attach it
// to the transaction. Since there is 1 transaction per block, the
// blocknumber is used as the key.
txMeta := ReadTransactionMeta(db, *blockNumber) txMeta := ReadTransactionMeta(db, *blockNumber)
if txMeta != nil { if txMeta != nil {
tx.SetTransactionMeta(txMeta) tx.SetTransactionMeta(txMeta)
......
...@@ -232,6 +232,11 @@ func (s *StateDB) GetBalance(addr common.Address) *big.Int { ...@@ -232,6 +232,11 @@ func (s *StateDB) GetBalance(addr common.Address) *big.Int {
return common.Big0 return common.Big0
} }
// UsingOVM
// Read the account's balance from the state. This is used
// because ETH is an ERC20. This function specifically looks
// up the storage slot of the users balance. It is fragile to any
// changes in storage layout.
func (s *StateDB) GetOVMBalance(addr common.Address) *big.Int { func (s *StateDB) GetOVMBalance(addr common.Address) *big.Int {
eth := common.HexToAddress("0x4200000000000000000000000000000000000006") eth := common.HexToAddress("0x4200000000000000000000000000000000000006")
position := big.NewInt(0) position := big.NewInt(0)
......
...@@ -89,6 +89,10 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo ...@@ -89,6 +89,10 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
return nil, err return nil, err
} }
} else { } else {
// The transaction must be modified when running the OVM. The
// transaction fields that the user signs must be ABI encoded and then
// turned into the calldata of the transaction and the `to` field has to
// be updated to be the sequencer entrypoint.
decompressor := config.StateDump.Accounts["OVM_SequencerEntrypoint"] decompressor := config.StateDump.Accounts["OVM_SequencerEntrypoint"]
msg, err = AsOvmMessage(tx, types.MakeSigner(config, header.Number), decompressor.Address, header.GasLimit) msg, err = AsOvmMessage(tx, types.MakeSigner(config, header.Number), decompressor.Address, header.GasLimit)
if err != nil { if err != nil {
...@@ -98,6 +102,12 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo ...@@ -98,6 +102,12 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
// Create a new context to be used in the EVM environment // Create a new context to be used in the EVM environment
context := NewEVMContext(msg, header, bc, author) context := NewEVMContext(msg, header, bc, author)
if vm.UsingOVM { if vm.UsingOVM {
// The `NUMBER` opcode returns the L1 blocknumber instead of the L2
// blocknumber, so set that here. In the future, this should be
// implemented by adding a new property to the EVM struct
// `L1BlockNumber` and updating `opNumber` to return that. This
// will help with keeping the difference in behavior maintainable over
// time
context.BlockNumber = msg.L1BlockNumber() context.BlockNumber = msg.L1BlockNumber()
} }
// Create a new environment which holds all relevant information // Create a new environment which holds all relevant information
......
...@@ -160,6 +160,10 @@ func (st *StateTransition) useGas(amount uint64) error { ...@@ -160,6 +160,10 @@ func (st *StateTransition) useGas(amount uint64) error {
func (st *StateTransition) buyGas() error { func (st *StateTransition) buyGas() error {
mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice)
// There is no native ETH, there is OVM_ETH which is an ERC20.
// Sufficient user balance is checked when the user sends the transaction
// via RPC through very similar checks as to when a transaction enters
// the layer one mempool. Deposits skip the check
if !vm.UsingOVM { if !vm.UsingOVM {
if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 { if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 {
return errInsufficientBalanceForGas return errInsufficientBalanceForGas
...@@ -171,6 +175,8 @@ func (st *StateTransition) buyGas() error { ...@@ -171,6 +175,8 @@ func (st *StateTransition) buyGas() error {
st.gas += st.msg.Gas() st.gas += st.msg.Gas()
st.initialGas = st.msg.Gas() st.initialGas = st.msg.Gas()
// Do not subtract the gas from the user balance when running OVM.
// This is handled in the Solidity contracts to enable to fraud proof
if !vm.UsingOVM { if !vm.UsingOVM {
st.state.SubBalance(st.msg.From(), mgval) st.state.SubBalance(st.msg.From(), mgval)
} }
...@@ -182,8 +188,10 @@ func (st *StateTransition) preCheck() error { ...@@ -182,8 +188,10 @@ func (st *StateTransition) preCheck() error {
if st.msg.CheckNonce() { if st.msg.CheckNonce() {
nonce := st.state.GetNonce(st.msg.From()) nonce := st.state.GetNonce(st.msg.From())
if nonce < st.msg.Nonce() { if nonce < st.msg.Nonce() {
// Skip the nonce check for L1 to L2 transactions. They do not
// increment a nonce in the state and they also ecrecover to
// `address(0)`
if vm.UsingOVM { if vm.UsingOVM {
// The nonce never increments for L1ToL2 txs
if st.msg.QueueOrigin() == types.QueueOriginL1ToL2 { if st.msg.QueueOrigin() == types.QueueOriginL1ToL2 {
return st.buyGas() return st.buyGas()
} }
...@@ -205,7 +213,9 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo ...@@ -205,7 +213,9 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
} }
if vm.UsingOVM { if vm.UsingOVM {
// OVM_ENABLED // When the execution is not an `eth_call`, abi encode the user transaction
// and place it in the calldata of the msg struct so that the user
// transaction can be passed to the system contracts via the calldata
if st.evm.EthCallSender == nil { if st.evm.EthCallSender == nil {
st.msg, err = toExecutionManagerRun(st.evm, st.msg) st.msg, err = toExecutionManagerRun(st.evm, st.msg)
} }
...@@ -221,8 +231,6 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo ...@@ -221,8 +231,6 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber) istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber)
contractCreation := msg.To() == nil contractCreation := msg.To() == nil
// OVM_ADDITION
// TODO(mark): pay intrinsic gas function needs to be updated
gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul) gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul)
if err != nil { if err != nil {
return nil, 0, false, err return nil, 0, false, err
...@@ -258,7 +266,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo ...@@ -258,7 +266,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
} else { } else {
// Increment the nonce for the next transaction // Increment the nonce for the next transaction
if !vm.UsingOVM { if !vm.UsingOVM {
// OVM_DISABLED // Do not set the nonce because that is handled in the Solidity
// contracts.
st.state.SetNonce(msg.From(), st.state.GetNonce(msg.From())+1) st.state.SetNonce(msg.From(), st.state.GetNonce(msg.From())+1)
} }
...@@ -273,13 +282,14 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo ...@@ -273,13 +282,14 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
st.refundGas() st.refundGas()
if !vm.UsingOVM { if !vm.UsingOVM {
// OVM_DISABLED // Do not pay the gas to the coinbase address when running the OVM
st.state.AddBalance(evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) st.state.AddBalance(evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
} }
return ret, st.gasUsed(), vmerr != nil, err return ret, st.gasUsed(), vmerr != nil, err
} }
func (st *StateTransition) refundGas() { func (st *StateTransition) refundGas() {
// Do not refund any gas when running the OVM
if vm.UsingOVM { if vm.UsingOVM {
return return
} }
......
...@@ -403,44 +403,12 @@ func (s *TxByPrice) Pop() interface{} { ...@@ -403,44 +403,12 @@ func (s *TxByPrice) Pop() interface{} {
return x return x
} }
type TxByIndexAndPrice Transactions
func (s TxByIndexAndPrice) Len() int { return len(s) }
func (s TxByIndexAndPrice) Less(i, j int) bool {
metai, metaj := s[i].GetMeta(), s[j].GetMeta()
// They should never be the same integer but they
// can both be nil. Sort by gasPrice in this case.
if metai.Index == nil && metaj.Index == nil {
return s[i].data.Price.Cmp(s[j].data.Price) > 0
}
// When the index is nil, it means that it is unknown. This
// indicates queue origin sequencer.
if metai.Index == nil && metaj.Index != nil {
return false
}
if metai.Index != nil && metaj.Index == nil {
return true
}
return *metai.Index < *metaj.Index
}
func (s TxByIndexAndPrice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s *TxByIndexAndPrice) Push(x interface{}) {
*s = append(*s, x.(*Transaction))
}
func (s *TxByIndexAndPrice) Pop() interface{} {
old := *s
n := len(old)
x := old[n-1]
*s = old[0 : n-1]
return x
}
// TransactionsByPriceAndNonce represents a set of transactions that can return // TransactionsByPriceAndNonce represents a set of transactions that can return
// transactions in a profit-maximizing sorted order, while supporting removing // transactions in a profit-maximizing sorted order, while supporting removing
// entire batches of transactions for non-executable accounts. // entire batches of transactions for non-executable accounts.
type TransactionsByPriceAndNonce struct { type TransactionsByPriceAndNonce struct {
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions txs map[common.Address]Transactions // Per account nonce-sorted list of transactions
heads TxByIndexAndPrice // Next transaction for each unique account (price heap) heads TxByPrice // Next transaction for each unique account (price heap)
signer Signer // Signer for the set of transactions signer Signer // Signer for the set of transactions
} }
...@@ -451,7 +419,7 @@ type TransactionsByPriceAndNonce struct { ...@@ -451,7 +419,7 @@ type TransactionsByPriceAndNonce struct {
// if after providing it to the constructor. // if after providing it to the constructor.
func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions) *TransactionsByPriceAndNonce { func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions) *TransactionsByPriceAndNonce {
// Initialize a price based heap with the head transactions // Initialize a price based heap with the head transactions
heads := make(TxByIndexAndPrice, 0, len(txs)) heads := make(TxByPrice, 0, len(txs))
for from, accTxs := range txs { for from, accTxs := range txs {
// This prevents a panic, not ideal. // This prevents a panic, not ideal.
if len(accTxs) > 0 { if len(accTxs) > 0 {
......
...@@ -558,18 +558,6 @@ type StorageResult struct { ...@@ -558,18 +558,6 @@ type StorageResult struct {
Proof []string `json:"proof"` Proof []string `json:"proof"`
} }
// Result structs for GetStateDiffProof
type StateDiffProof struct {
Header *HeaderMeta `json:"header"`
Accounts []AccountResult `json:"accounts"`
}
type HeaderMeta struct {
Number *big.Int `json:"number"`
Hash common.Hash `json:"hash"`
StateRoot common.Hash `json:"stateRoot"`
Timestamp uint64 `json:"timestamp"`
}
// GetProof returns the Merkle-proof for a given account and optionally some storage keys. // GetProof returns the Merkle-proof for a given account and optionally some storage keys.
func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) {
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
......
...@@ -205,10 +205,6 @@ func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) ...@@ -205,10 +205,6 @@ func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
return b.eth.txPool.Add(ctx, signedTx) return b.eth.txPool.Add(ctx, signedTx)
} }
func (b *LesApiBackend) SetTimestamp(timestamp int64) {
// Intentionally empty because this is not needed for LightChain
}
func (b *LesApiBackend) RemoveTx(txHash common.Hash) { func (b *LesApiBackend) RemoveTx(txHash common.Hash) {
b.eth.txPool.RemoveTx(txHash) b.eth.txPool.RemoveTx(txHash)
} }
......
...@@ -446,25 +446,21 @@ func (pool *TxPool) Add(ctx context.Context, tx *types.Transaction) error { ...@@ -446,25 +446,21 @@ func (pool *TxPool) Add(ctx context.Context, tx *types.Transaction) error {
return nil return nil
} }
// AddBatch adds all valid transactions to the pool and passes them to // AddTransactions adds all valid transactions to the pool and passes them to
// the tx relay backend // the tx relay backend
func (pool *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) []error { func (pool *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) {
pool.mu.Lock() pool.mu.Lock()
defer pool.mu.Unlock() defer pool.mu.Unlock()
var sendTx types.Transactions var sendTx types.Transactions
errors := make([]error, len(txs)) for _, tx := range txs {
for i, tx := range txs {
if err := pool.add(ctx, tx); err == nil { if err := pool.add(ctx, tx); err == nil {
sendTx = append(sendTx, tx) sendTx = append(sendTx, tx)
} else {
errors[i] = err
} }
} }
if len(sendTx) > 0 { if len(sendTx) > 0 {
pool.relay.Send(sendTx) pool.relay.Send(sendTx)
} }
return errors
} }
// GetTransaction returns a transaction if it is contained in the pool // GetTransaction returns a transaction if it is contained in the pool
......
...@@ -192,6 +192,7 @@ func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consens ...@@ -192,6 +192,7 @@ func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consens
} }
func TestGenerateBlockAndImportEthash(t *testing.T) { func TestGenerateBlockAndImportEthash(t *testing.T) {
t.Skip("OVM")
testGenerateBlockAndImport(t, false) testGenerateBlockAndImport(t, false)
} }
......
...@@ -161,6 +161,8 @@ func (t *Trie) Update(key, value []byte) { ...@@ -161,6 +161,8 @@ func (t *Trie) Update(key, value []byte) {
// stored in the trie. // stored in the trie.
// //
// If a node was not found in the database, a MissingNodeError is returned. // If a node was not found in the database, a MissingNodeError is returned.
// UsingOVM
// Do not delete empty nodes
func (t *Trie) TryUpdate(key, value []byte) error { func (t *Trie) TryUpdate(key, value []byte) error {
k := keybytesToHex(key) k := keybytesToHex(key)
_, n, err := t.insert(t.root, nil, k, valueNode(value)) _, n, err := t.insert(t.root, nil, k, valueNode(value))
......
...@@ -11,8 +11,8 @@ import { iOVM_L2ToL1MessagePasser } from "../../iOVM/predeploys/iOVM_L2ToL1Messa ...@@ -11,8 +11,8 @@ import { iOVM_L2ToL1MessagePasser } from "../../iOVM/predeploys/iOVM_L2ToL1Messa
* _verifyStorageProof function, which verifies the existence of the transaction hash in this * _verifyStorageProof function, which verifies the existence of the transaction hash in this
* contract's `sentMessages` mapping. * contract's `sentMessages` mapping.
* *
* Compiler used: solc * Compiler used: optimistic-solc
* Runtime target: EVM * Runtime target: OVM
*/ */
contract OVM_L2ToL1MessagePasser is iOVM_L2ToL1MessagePasser { contract OVM_L2ToL1MessagePasser is iOVM_L2ToL1MessagePasser {
......
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