Commit 2fcbe4ba authored by Axel Kingsley's avatar Axel Kingsley Committed by GitHub

SuperSystem: Add Emitter Contract - Basic Message Passing (#11956)

* Add Emitter Contract

* Emitter Contract and Bindings

* AddL2RPC without Stopping

* Rename testdata folder to contracts

* update generate.sh

* update solidity and gen script
parent 3c3a3113
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package emit
import (
"errors"
"math/big"
"strings"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)
// Reference imports to suppress errors if they are not otherwise used.
var (
_ = errors.New
_ = big.NewInt
_ = strings.NewReader
_ = ethereum.NotFound
_ = bind.Bind
_ = common.Big1
_ = types.BloomLookup
_ = event.NewSubscription
_ = abi.ConvertType
)
// EmitMetaData contains all meta data concerning the Emit contract.
var EmitMetaData = &bind.MetaData{
ABI: "[{\"type\":\"function\",\"name\":\"emitData\",\"inputs\":[{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"DataEmitted\",\"inputs\":[{\"name\":\"_data\",\"type\":\"bytes\",\"indexed\":true,\"internalType\":\"bytes\"}],\"anonymous\":false}]",
Bin: "0x6080604052348015600e575f80fd5b5060ff8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a",
}
// EmitABI is the input ABI used to generate the binding from.
// Deprecated: Use EmitMetaData.ABI instead.
var EmitABI = EmitMetaData.ABI
// EmitBin is the compiled bytecode used for deploying new contracts.
// Deprecated: Use EmitMetaData.Bin instead.
var EmitBin = EmitMetaData.Bin
// DeployEmit deploys a new Ethereum contract, binding an instance of Emit to it.
func DeployEmit(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Emit, error) {
parsed, err := EmitMetaData.GetAbi()
if err != nil {
return common.Address{}, nil, nil, err
}
if parsed == nil {
return common.Address{}, nil, nil, errors.New("GetABI returned nil")
}
address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EmitBin), backend)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &Emit{EmitCaller: EmitCaller{contract: contract}, EmitTransactor: EmitTransactor{contract: contract}, EmitFilterer: EmitFilterer{contract: contract}}, nil
}
// Emit is an auto generated Go binding around an Ethereum contract.
type Emit struct {
EmitCaller // Read-only binding to the contract
EmitTransactor // Write-only binding to the contract
EmitFilterer // Log filterer for contract events
}
// EmitCaller is an auto generated read-only Go binding around an Ethereum contract.
type EmitCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// EmitTransactor is an auto generated write-only Go binding around an Ethereum contract.
type EmitTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// EmitFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type EmitFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// EmitSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type EmitSession struct {
Contract *Emit // Generic contract binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// EmitCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type EmitCallerSession struct {
Contract *EmitCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// EmitTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type EmitTransactorSession struct {
Contract *EmitTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// EmitRaw is an auto generated low-level Go binding around an Ethereum contract.
type EmitRaw struct {
Contract *Emit // Generic contract binding to access the raw methods on
}
// EmitCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type EmitCallerRaw struct {
Contract *EmitCaller // Generic read-only contract binding to access the raw methods on
}
// EmitTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type EmitTransactorRaw struct {
Contract *EmitTransactor // Generic write-only contract binding to access the raw methods on
}
// NewEmit creates a new instance of Emit, bound to a specific deployed contract.
func NewEmit(address common.Address, backend bind.ContractBackend) (*Emit, error) {
contract, err := bindEmit(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &Emit{EmitCaller: EmitCaller{contract: contract}, EmitTransactor: EmitTransactor{contract: contract}, EmitFilterer: EmitFilterer{contract: contract}}, nil
}
// NewEmitCaller creates a new read-only instance of Emit, bound to a specific deployed contract.
func NewEmitCaller(address common.Address, caller bind.ContractCaller) (*EmitCaller, error) {
contract, err := bindEmit(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &EmitCaller{contract: contract}, nil
}
// NewEmitTransactor creates a new write-only instance of Emit, bound to a specific deployed contract.
func NewEmitTransactor(address common.Address, transactor bind.ContractTransactor) (*EmitTransactor, error) {
contract, err := bindEmit(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &EmitTransactor{contract: contract}, nil
}
// NewEmitFilterer creates a new log filterer instance of Emit, bound to a specific deployed contract.
func NewEmitFilterer(address common.Address, filterer bind.ContractFilterer) (*EmitFilterer, error) {
contract, err := bindEmit(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &EmitFilterer{contract: contract}, nil
}
// bindEmit binds a generic wrapper to an already deployed contract.
func bindEmit(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := EmitMetaData.GetAbi()
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_Emit *EmitRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _Emit.Contract.EmitCaller.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_Emit *EmitRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _Emit.Contract.EmitTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_Emit *EmitRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _Emit.Contract.EmitTransactor.contract.Transact(opts, method, params...)
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_Emit *EmitCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _Emit.Contract.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_Emit *EmitTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _Emit.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_Emit *EmitTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _Emit.Contract.contract.Transact(opts, method, params...)
}
// EmitData is a paid mutator transaction binding the contract method 0xd836083e.
//
// Solidity: function emitData(bytes _data) returns()
func (_Emit *EmitTransactor) EmitData(opts *bind.TransactOpts, _data []byte) (*types.Transaction, error) {
return _Emit.contract.Transact(opts, "emitData", _data)
}
// EmitData is a paid mutator transaction binding the contract method 0xd836083e.
//
// Solidity: function emitData(bytes _data) returns()
func (_Emit *EmitSession) EmitData(_data []byte) (*types.Transaction, error) {
return _Emit.Contract.EmitData(&_Emit.TransactOpts, _data)
}
// EmitData is a paid mutator transaction binding the contract method 0xd836083e.
//
// Solidity: function emitData(bytes _data) returns()
func (_Emit *EmitTransactorSession) EmitData(_data []byte) (*types.Transaction, error) {
return _Emit.Contract.EmitData(&_Emit.TransactOpts, _data)
}
// EmitDataEmittedIterator is returned from FilterDataEmitted and is used to iterate over the raw logs and unpacked data for DataEmitted events raised by the Emit contract.
type EmitDataEmittedIterator struct {
Event *EmitDataEmitted // Event containing the contract specifics and raw log
contract *bind.BoundContract // Generic contract to use for unpacking event data
event string // Event name to use for unpacking event data
logs chan types.Log // Log channel receiving the found contract events
sub ethereum.Subscription // Subscription for errors, completion and termination
done bool // Whether the subscription completed delivering logs
fail error // Occurred error to stop iteration
}
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *EmitDataEmittedIterator) Next() bool {
// If the iterator failed, stop iterating
if it.fail != nil {
return false
}
// If the iterator completed, deliver directly whatever's available
if it.done {
select {
case log := <-it.logs:
it.Event = new(EmitDataEmitted)
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
default:
return false
}
}
// Iterator still in progress, wait for either a data or an error event
select {
case log := <-it.logs:
it.Event = new(EmitDataEmitted)
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
case err := <-it.sub.Err():
it.done = true
it.fail = err
return it.Next()
}
}
// Error returns any retrieval or parsing error occurred during filtering.
func (it *EmitDataEmittedIterator) Error() error {
return it.fail
}
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *EmitDataEmittedIterator) Close() error {
it.sub.Unsubscribe()
return nil
}
// EmitDataEmitted represents a DataEmitted event raised by the Emit contract.
type EmitDataEmitted struct {
Data common.Hash
Raw types.Log // Blockchain specific contextual infos
}
// FilterDataEmitted is a free log retrieval operation binding the contract event 0xe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c.
//
// Solidity: event DataEmitted(bytes indexed _data)
func (_Emit *EmitFilterer) FilterDataEmitted(opts *bind.FilterOpts, _data [][]byte) (*EmitDataEmittedIterator, error) {
var _dataRule []interface{}
for _, _dataItem := range _data {
_dataRule = append(_dataRule, _dataItem)
}
logs, sub, err := _Emit.contract.FilterLogs(opts, "DataEmitted", _dataRule)
if err != nil {
return nil, err
}
return &EmitDataEmittedIterator{contract: _Emit.contract, event: "DataEmitted", logs: logs, sub: sub}, nil
}
// WatchDataEmitted is a free log subscription operation binding the contract event 0xe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c.
//
// Solidity: event DataEmitted(bytes indexed _data)
func (_Emit *EmitFilterer) WatchDataEmitted(opts *bind.WatchOpts, sink chan<- *EmitDataEmitted, _data [][]byte) (event.Subscription, error) {
var _dataRule []interface{}
for _, _dataItem := range _data {
_dataRule = append(_dataRule, _dataItem)
}
logs, sub, err := _Emit.contract.WatchLogs(opts, "DataEmitted", _dataRule)
if err != nil {
return nil, err
}
return event.NewSubscription(func(quit <-chan struct{}) error {
defer sub.Unsubscribe()
for {
select {
case log := <-logs:
// New log arrived, parse the event and forward to the user
event := new(EmitDataEmitted)
if err := _Emit.contract.UnpackLog(event, "DataEmitted", log); err != nil {
return err
}
event.Raw = log
select {
case sink <- event:
case err := <-sub.Err():
return err
case <-quit:
return nil
}
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
}), nil
}
// ParseDataEmitted is a log parse operation binding the contract event 0xe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c.
//
// Solidity: event DataEmitted(bytes indexed _data)
func (_Emit *EmitFilterer) ParseDataEmitted(log types.Log) (*EmitDataEmitted, error) {
event := new(EmitDataEmitted)
if err := _Emit.contract.UnpackLog(event, "DataEmitted", log); err != nil {
return nil, err
}
event.Raw = log
return event, nil
}
################################################################
# PROFILE: DEFAULT (Local) #
################################################################
[profile.default]
# Compilation settings
src = 'src'
out = 'build'
script = 'scripts'
optimizer = true
optimizer_runs = 999999
remappings = []
extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout']
bytecode_hash = 'none'
build_info_path = 'artifacts/build-info'
ast = true
evm_version = "cancun"
# 5159 error code is selfdestruct error code
ignored_error_codes = ["transient-storage", "code-size", "init-code-size", 5159]
# We set the gas limit to max int64 to avoid running out of gas during testing, since the default
# gas limit is 1B and some of our tests require more gas than that, such as `test_callWithMinGas_noLeakageLow_succeeds`.
# We use this gas limit since it was the default gas limit prior to https://github.com/foundry-rs/foundry/pull/8274.
# Due to toml-rs limitations, if you increase the gas limit above this value it must be a string.
gas_limit = 9223372036854775807
# Test / Script Runner Settings
ffi = false
fs_permissions = []
libs = ["node_modules", "lib"]
#!/bin/sh
set -euo
forge build
cd build/emit.sol
cat EmitEvent.json | jq -r '.bytecode.object' > EmitEvent.bin
cat EmitEvent.json | jq '.abi' > EmitEvent.abi
cd ../..
abigen --abi ./build/emit.sol/EmitEvent.abi --bin ./build/emit.sol/EmitEvent.bin --pkg emit --out ./emit.go
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
contract EmitEvent {
// Define an event that logs the emitted data
event DataEmitted(bytes indexed _data);
// Function that takes calldata and emits the data as an event
function emitData(bytes calldata _data) external {
emit DataEmitted(_data);
}
}
[
{
"type": "function",
"name": "emitData",
"inputs": [
{
"name": "data",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "event",
"name": "DataEmitted",
"inputs": [
{
"name": "data",
"type": "bytes",
"indexed": true,
"internalType": "bytes"
}
],
"anonymous": false
}
]
0x6080604052348015600e575f80fd5b5060ff8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a
{"abi":[{"type":"function","name":"emitData","inputs":[{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"DataEmitted","inputs":[{"name":"data","type":"bytes","indexed":true,"internalType":"bytes"}],"anonymous":false}],"bytecode":{"object":"0x6080604052348015600e575f80fd5b5060ff8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a","sourceMap":"58:275:0:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a","sourceMap":"58:275:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;244:87;;;;;;:::i;:::-;;:::i;:::-;;;319:4;;307:17;;;;;;;:::i;:::-;;;;;;;;;;;;;;;244:87;;:::o;14:591:1:-;84:6;92;145:2;133:9;124:7;120:23;116:32;113:52;;;161:1;158;151:12;113:52;201:9;188:23;230:18;271:2;263:6;260:14;257:34;;;287:1;284;277:12;257:34;325:6;314:9;310:22;300:32;;370:7;363:4;359:2;355:13;351:27;341:55;;392:1;389;382:12;341:55;432:2;419:16;458:2;450:6;447:14;444:34;;;474:1;471;464:12;444:34;519:7;514:2;505:6;501:2;497:15;493:24;490:37;487:57;;;540:1;537;530:12;487:57;571:2;563:11;;;;;593:6;;-1:-1:-1;14:591:1;;-1:-1:-1;;;;14:591:1:o;610:271::-;793:6;785;780:3;767:33;749:3;819:16;;844:13;;;819:16;610:271;-1:-1:-1;610:271:1:o","linkReferences":{}},"methodIdentifiers":{"emitData(bytes)":"d836083e"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"DataEmitted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"emitData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/emit.sol\":\"EmitEvent\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"src/emit.sol\":{\"keccak256\":\"0xdee458d231a8b41e5ba097be7258a6da27501fafb2a6f865705953458aecafbf\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://912d125138604114be66c8d044a39ef83861e6dc2d5fe3be32a1a4e014ea2763\",\"dweb:/ipfs/QmUx5NRsTXzujjwU1SXMSNp5Wjys3v5PDLuhdpoAyCy7nx\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.25+commit.b61c2a91"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes","name":"data","type":"bytes","indexed":true}],"type":"event","name":"DataEmitted","anonymous":false},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"emitData"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/emit.sol":"EmitEvent"},"evmVersion":"cancun","libraries":{}},"sources":{"src/emit.sol":{"keccak256":"0xdee458d231a8b41e5ba097be7258a6da27501fafb2a6f865705953458aecafbf","urls":["bzz-raw://912d125138604114be66c8d044a39ef83861e6dc2d5fe3be32a1a4e014ea2763","dweb:/ipfs/QmUx5NRsTXzujjwU1SXMSNp5Wjys3v5PDLuhdpoAyCy7nx"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"src/emit.sol","id":17,"exportedSymbols":{"EmitEvent":[16]},"nodeType":"SourceUnit","src":"32:302:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:24:0","nodes":[],"literals":["solidity","^","0.8",".15"]},{"id":16,"nodeType":"ContractDefinition","src":"58:275:0","nodes":[{"id":5,"nodeType":"EventDefinition","src":"133:38:0","nodes":[],"anonymous":false,"eventSelector":"e00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c","name":"DataEmitted","nameLocation":"139:11:0","parameters":{"id":4,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"indexed":true,"mutability":"mutable","name":"data","nameLocation":"165:4:0","nodeType":"VariableDeclaration","scope":5,"src":"151:18:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":2,"name":"bytes","nodeType":"ElementaryTypeName","src":"151:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"150:20:0"}},{"id":15,"nodeType":"FunctionDefinition","src":"244:87:0","nodes":[],"body":{"id":14,"nodeType":"Block","src":"292:39:0","nodes":[],"statements":[{"eventCall":{"arguments":[{"id":11,"name":"data","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":7,"src":"319:4:0","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}],"id":10,"name":"DataEmitted","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":5,"src":"307:11:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory)"}},"id":12,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"307:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":13,"nodeType":"EmitStatement","src":"302:22:0"}]},"functionSelector":"d836083e","implemented":true,"kind":"function","modifiers":[],"name":"emitData","nameLocation":"253:8:0","parameters":{"id":8,"nodeType":"ParameterList","parameters":[{"constant":false,"id":7,"mutability":"mutable","name":"data","nameLocation":"277:4:0","nodeType":"VariableDeclaration","scope":15,"src":"262:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":6,"name":"bytes","nodeType":"ElementaryTypeName","src":"262:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"261:21:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[],"src":"292:0:0"},"scope":16,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"EmitEvent","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[16],"name":"EmitEvent","nameLocation":"67:9:0","scope":17,"usedErrors":[],"usedEvents":[5]}],"license":"MIT"},"id":0}
\ No newline at end of file
......@@ -2,6 +2,7 @@ package interop
import (
"context"
"fmt"
"math/big"
"testing"
"time"
......@@ -54,9 +55,6 @@ func TestInteropTrivial(t *testing.T) {
expectedBalance, _ := big.NewInt(0).SetString("10000000000000000000000000", 10)
require.Equal(t, expectedBalance, bobBalance)
// sleep for a bit to allow the chain to start
time.Sleep(30 * time.Second)
// send a tx from Alice to Bob
s2.SendL2Tx(
chainA,
......@@ -86,4 +84,17 @@ func TestInteropTrivial(t *testing.T) {
require.NoError(t, err)
expectedBalance, _ = big.NewInt(0).SetString("10000000000000000000000000", 10)
require.Equal(t, expectedBalance, bobBalance)
s2.DeployEmitterContract(chainA, "Alice")
rec := s2.EmitData(chainA, "Alice", "0x1234567890abcdef")
fmt.Println("Result of emitting event:", rec)
s2.DeployEmitterContract(chainB, "Alice")
rec = s2.EmitData(chainB, "Alice", "0x1234567890abcdef")
fmt.Println("Result of emitting event:", rec)
time.Sleep(10 * time.Second)
}
......@@ -10,11 +10,13 @@ import (
"testing"
"time"
emit "github.com/ethereum-optimism/optimism/op-e2e/interop/contracts"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
......@@ -86,6 +88,12 @@ type SuperSystem interface {
SendL2Tx(network string, username string, applyTxOpts helpers.TxOptsFn) *types.Receipt
// get the address for a user on an L2
Address(network string, username string) common.Address
// Deploy the Emitter Contract, which emits Event Logs
DeployEmitterContract(network string, username string) common.Address
// Use the Emitter Contract to emit an Event Log
EmitData(network string, username string, data string) *types.Receipt
// Access a contract on a network by name
Contract(network string, contractName string) interface{}
}
// NewSuperSystem creates a new SuperSystem from a recipe. It creates an interopE2ESystem.
......@@ -123,6 +131,7 @@ type l2Set struct {
batcher *bss.BatcherService
operatorKeys map[devkeys.ChainOperatorRole]ecdsa.PrivateKey
userKeys map[string]ecdsa.PrivateKey
contracts map[string]interface{}
}
// prepareHDWallet creates a new HD wallet to derive keys from
......@@ -401,6 +410,7 @@ func (s *interopE2ESystem) newL2(id string, l2Out *interopgen.L2Output) l2Set {
batcher: batcher,
operatorKeys: operatorKeys,
userKeys: make(map[string]ecdsa.PrivateKey),
contracts: make(map[string]interface{}),
}
}
......@@ -591,12 +601,60 @@ func (s *interopE2ESystem) SendL2Tx(
) *types.Receipt {
senderSecret := s.UserKey(id, sender)
require.NotNil(s.t, senderSecret, "no secret found for sender %s", sender)
nonce, err := s.L2GethClient(id).PendingNonceAt(context.Background(), crypto.PubkeyToAddress(senderSecret.PublicKey))
require.NoError(s.t, err, "failed to get nonce")
newApply := func(opts *helpers.TxOpts) {
applyTxOpts(opts)
opts.Nonce = nonce
}
return helpers.SendL2TxWithID(
s.t,
s.l2s[id].chainID,
s.L2GethClient(id),
&senderSecret,
applyTxOpts)
newApply)
}
func (s *interopE2ESystem) DeployEmitterContract(
id string,
sender string,
) common.Address {
secret := s.UserKey(id, sender)
auth, err := bind.NewKeyedTransactorWithChainID(&secret, s.l2s[id].chainID)
require.NoError(s.t, err)
auth.GasLimit = uint64(3000000)
auth.GasPrice = big.NewInt(20000000000)
address, _, _, err := emit.DeployEmit(auth, s.L2GethClient(id))
require.NoError(s.t, err)
contract, err := emit.NewEmit(address, s.L2GethClient(id))
require.NoError(s.t, err)
s.l2s[id].contracts["emitter"] = contract
return address
}
func (s *interopE2ESystem) EmitData(
id string,
sender string,
data string,
) *types.Receipt {
secret := s.UserKey(id, sender)
auth, err := bind.NewKeyedTransactorWithChainID(&secret, s.l2s[id].chainID)
require.NoError(s.t, err)
auth.GasLimit = uint64(3000000)
auth.GasPrice = big.NewInt(20000000000)
contract := s.Contract(id, "emitter").(*emit.Emit)
tx, err := contract.EmitTransactor.EmitData(auth, []byte(data))
require.NoError(s.t, err)
receipt, err := bind.WaitMined(context.Background(), s.L2GethClient(id), tx)
require.NoError(s.t, err)
return receipt
}
func (s *interopE2ESystem) Contract(id string, name string) interface{} {
return s.l2s[id].contracts[name]
}
func mustDial(t *testing.T, logger log.Logger) func(v string) *rpc.Client {
......
......@@ -68,8 +68,9 @@ func NewSupervisorBackend(ctx context.Context, logger log.Logger, m Metrics, cfg
}
// from the RPC strings, have the supervisor backend create a chain monitor
// don't start the monitor yet, as we will start all monitors at once when Start is called
for _, rpc := range cfg.L2RPCs {
err := super.addFromRPC(ctx, logger, rpc)
err := super.addFromRPC(ctx, logger, rpc, false)
if err != nil {
return nil, fmt.Errorf("failed to add chain monitor for rpc %v: %w", rpc, err)
}
......@@ -79,7 +80,8 @@ func NewSupervisorBackend(ctx context.Context, logger log.Logger, m Metrics, cfg
// addFromRPC adds a chain monitor to the supervisor backend from an rpc endpoint
// it does not expect to be called after the backend has been started
func (su *SupervisorBackend) addFromRPC(ctx context.Context, logger log.Logger, rpc string) error {
// it will start the monitor if shouldStart is true
func (su *SupervisorBackend) addFromRPC(ctx context.Context, logger log.Logger, rpc string, shouldStart bool) error {
// create the rpc client, which yields the chain id
rpcClient, chainID, err := createRpcClient(ctx, logger, rpc)
if err != nil {
......@@ -96,12 +98,18 @@ func (su *SupervisorBackend) addFromRPC(ctx context.Context, logger log.Logger,
if err != nil {
return fmt.Errorf("failed to create logdb for chain %v at %v: %w", chainID, path, err)
}
if su.chainMonitors[chainID] != nil {
return fmt.Errorf("chain monitor for chain %v already exists", chainID)
}
monitor, err := source.NewChainMonitor(ctx, logger, cm, chainID, rpc, rpcClient, su.db)
if err != nil {
return fmt.Errorf("failed to create monitor for rpc %v: %w", rpc, err)
}
if su.chainMonitors[chainID] != nil {
return fmt.Errorf("chain monitor for chain %v already exists", chainID)
// start the monitor if requested
if shouldStart {
if err := monitor.Start(); err != nil {
return fmt.Errorf("failed to start monitor for rpc %v: %w", rpc, err)
}
}
su.chainMonitors[chainID] = monitor
su.db.AddLogDB(chainID, logDB)
......@@ -172,15 +180,8 @@ func (su *SupervisorBackend) Close() error {
// AddL2RPC adds a new L2 chain to the supervisor backend
// it stops and restarts the backend to add the new chain
func (su *SupervisorBackend) AddL2RPC(ctx context.Context, rpc string) error {
if err := su.Stop(ctx); err != nil {
return fmt.Errorf("failed to stop backend: %w", err)
}
su.logger.Info("temporarily stopped the backend to add a new L2 RPC", "rpc", rpc)
if err := su.addFromRPC(ctx, su.logger, rpc); err != nil {
return fmt.Errorf("failed to add chain monitor: %w", err)
}
su.logger.Info("added the new L2 RPC, starting supervisor again", "rpc", rpc)
return su.Start(ctx)
// start the monitor immediately, as the backend is assumed to already be running
return su.addFromRPC(ctx, su.logger, rpc, true)
}
func (su *SupervisorBackend) CheckMessage(identifier types.Identifier, payloadHash common.Hash) (types.SafetyLevel, error) {
......
......@@ -51,6 +51,7 @@ func NewChainsDB(logDBs map[types.ChainID]LogStorage, heads HeadsStorage, l log.
logDBs: logDBs,
heads: heads,
logger: l,
maintenanceReady: make(chan struct{}, 1),
}
}
......@@ -79,7 +80,7 @@ func (db *ChainsDB) Resume() error {
func (db *ChainsDB) StartCrossHeadMaintenance(ctx context.Context) {
go func() {
db.logger.Info("cross-head maintenance loop started")
// run the maintenance loop every 10 seconds for now
// run the maintenance loop every 1 seconds for now
ticker := time.NewTicker(time.Second * 1)
for {
select {
......@@ -200,8 +201,7 @@ func (db *ChainsDB) UpdateCrossHeadsForChain(chainID types.ChainID, checker Safe
// based on the provided SafetyChecker. The SafetyChecker is used to determine
// the safety of each log entry in the database, and the cross-head associated with it.
func (db *ChainsDB) UpdateCrossHeads(checker SafetyChecker) error {
currentHeads := db.heads.Current()
for chainID := range currentHeads.Chains {
for chainID := range db.logDBs {
err := db.UpdateCrossHeadsForChain(chainID, checker)
if err != nil {
return err
......
......@@ -54,7 +54,7 @@ func NewEntryDB(logger log.Logger, path string) (*EntryDB, error) {
lastEntryIdx: EntryIdx(size - 1),
}
if size*EntrySize != info.Size() {
logger.Warn("File size is nut a multiple of entry size. Truncating to last complete entry", "fileSize", size, "entrySize", EntrySize)
logger.Warn("File size is not a multiple of entry size. Truncating to last complete entry", "fileSize", size, "entrySize", EntrySize)
if err := db.recover(); err != nil {
return nil, fmt.Errorf("failed to recover database at %v: %w", path, err)
}
......
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