Commit 6b703c0d authored by vicotor's avatar vicotor

add chaindb and genesis

parent 411de197
......@@ -5,6 +5,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/exchain/go-exchain/exchain"
"github.com/exchain/go-exchain/exchain/chaindb"
nebulav1 "github.com/exchain/go-exchain/exchain/protocol/gen/go/nebula/v1"
"github.com/exchain/go-exchain/op-node/p2p"
"github.com/exchain/go-exchain/op-node/rollup/driver"
......@@ -13,79 +14,76 @@ import (
"math/big"
)
type EngineAPI struct {
type ExChainAPI struct {
chain chaindb.ChainDB
}
func (e *EngineAPI) BlockRefByNumber(ctx context.Context, num uint64) (eth.BlockRef, error) {
func (e *ExChainAPI) BlockRefByNumber(ctx context.Context, num uint64) (eth.BlockRef, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) FetchReceipts(ctx context.Context, blockHash common.Hash) (eth.BlockInfo, types.Receipts, error) {
func (e *ExChainAPI) FetchReceipts(ctx context.Context, blockHash common.Hash) (eth.BlockInfo, types.Receipts, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) OutputV0AtBlock(ctx context.Context, blockHash common.Hash) (*eth.OutputV0, error) {
func (e *ExChainAPI) OutputV0AtBlock(ctx context.Context, blockHash common.Hash) (*eth.OutputV0, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) ChainID(ctx context.Context) (*big.Int, error) {
func (e *ExChainAPI) ChainID(ctx context.Context) (*big.Int, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) NewPayload(params exchain.PayloadParams) (exchain.ExecutionResult, error) {
func (e *ExChainAPI) NewPayload(params exchain.PayloadParams) (exchain.ExecutionResult, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) ProcessPayload(block *nebulav1.Block) error {
func (e *ExChainAPI) ProcessPayload(block *nebulav1.Block) error {
//TODO implement me
panic("implement me")
}
//func (e *EngineAPI) PayloadByHash(ctx context.Context, hash common.Hash) (*eth.ExecutionPayloadEnvelope, error) {
// //TODO implement me
// panic("implement me")
//}
func (e *EngineAPI) PayloadByNumber(ctx context.Context, u uint64) (*eth.ExecutionPayloadEnvelope, error) {
func (e *ExChainAPI) PayloadByNumber(ctx context.Context, u uint64) (*eth.ExecutionPayloadEnvelope, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L2BlockRef, error) {
func (e *ExChainAPI) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L2BlockRef, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) L2BlockRefByHash(ctx context.Context, l2Hash common.Hash) (eth.L2BlockRef, error) {
func (e *ExChainAPI) L2BlockRefByHash(ctx context.Context, l2Hash common.Hash) (eth.L2BlockRef, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) L2BlockRefByNumber(ctx context.Context, num uint64) (eth.L2BlockRef, error) {
func (e *ExChainAPI) L2BlockRefByNumber(ctx context.Context, num uint64) (eth.L2BlockRef, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) SystemConfigByL2Hash(ctx context.Context, hash common.Hash) (eth.SystemConfig, error) {
func (e *ExChainAPI) SystemConfigByL2Hash(ctx context.Context, hash common.Hash) (eth.SystemConfig, error) {
//TODO implement me
panic("implement me")
}
func (e *EngineAPI) Close() {
func (e *ExChainAPI) Close() {
}
var (
_ p2p.L2Chain = (*EngineAPI)(nil)
_ sync.L2Chain = (*EngineAPI)(nil)
_ driver.L2Chain = (*EngineAPI)(nil)
_ p2p.L2Chain = (*ExChainAPI)(nil)
_ sync.L2Chain = (*ExChainAPI)(nil)
_ driver.L2Chain = (*ExChainAPI)(nil)
)
func NewEngineAPI(database exchain.Database) *EngineAPI {
return &EngineAPI{}
func NewEngineAPI(database chaindb.ChainDB) *ExChainAPI {
return &ExChainAPI{
chain: database,
}
}
This diff is collapsed.
package chaindb
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"strconv"
"strings"
)
type txEntry struct {
BlockNumber uint64
Index int64
}
func (e *txEntry) Bytes() []byte {
d := fmt.Sprintf("%d,%d", e.BlockNumber, e.Index)
return []byte(d)
}
func (e *txEntry) SetBytes(data []byte) error {
splits := strings.Split(string(data), ",")
if len(splits) != 2 {
return fmt.Errorf("invalid txEntry bytes")
}
e.BlockNumber, _ = strconv.ParseUint(splits[0], 10, 0)
e.Index, _ = strconv.ParseInt(splits[1], 10, 0)
return nil
}
func (m *chaindb) storeTxEntry(hash common.Hash, entry txEntry) error {
k := txEntryKey(hash)
return m.database.Put([]byte(k), entry.Bytes())
}
func (m *chaindb) getTxEntry(hash common.Hash) (txEntry, error) {
k := txEntryKey(hash)
v, err := m.database.Get([]byte(k))
if err != nil {
return txEntry{}, err
}
var entry = new(txEntry)
if err := entry.SetBytes(v); err != nil {
return txEntry{}, err
}
return *entry, nil
}
package chaindb
import (
"github.com/ethereum/go-ethereum/common"
"github.com/holiman/uint256"
"strings"
)
const (
BlockNumKeyPrefix = "bn-"
BlockHeaderPrefix = "bh-"
BlockBodyPrefix = "bd-"
BlockReceiptsPrefix = "br-"
BlockAccountsPrefix = "bcc-"
TransactionEntryPrefix = "te"
TransactionKeyPrefix = "tr-"
ReceiptKeyPrefix = "re-"
HeightKey = "hei-chain"
ChainIdKey = "chain-id"
)
func chainIdKey() string {
return ChainIdKey
}
func chainHeightKey() string {
return HeightKey
}
func blockHeaderKey(number *uint256.Int) string {
n := number.String()
s := make([]byte, 0, len(n)+len(BlockHeaderPrefix))
s = append(s, BlockHeaderPrefix...)
s = append(s, n...)
return string(s)
}
func blockBodyKey(number *uint256.Int) string {
n := number.String()
s := make([]byte, 0, len(n)+len(BlockBodyPrefix))
s = append(s, BlockBodyPrefix...)
s = append(s, n...)
return string(s)
}
func blockReceiptsKey(number *uint256.Int) string {
n := number.String()
s := make([]byte, 0, len(n)+len(BlockReceiptsPrefix))
s = append(s, BlockReceiptsPrefix...)
s = append(s, n...)
return string(s)
}
func blockNumKey(hash common.Hash) string {
n := strings.ToLower(hash.String())
s := make([]byte, 0, len(n)+len(BlockNumKeyPrefix))
s = append(s, BlockNumKeyPrefix...)
s = append(s, n...)
return string(s)
}
func txEntryKey(hash common.Hash) string {
h := hash.String()
s := make([]byte, 0, len(h)+len(TransactionEntryPrefix))
s = append(s, TransactionEntryPrefix...)
s = append(s, h...)
return string(s)
}
func transactionKey(hash common.Hash) string {
h := hash.String()
s := make([]byte, 0, len(h)+len(TransactionKeyPrefix))
s = append(s, TransactionKeyPrefix...)
s = append(s, h...)
return string(s)
}
func receiptKey(hash common.Hash) string {
h := hash.String()
s := make([]byte, 0, len(h)+len(ReceiptKeyPrefix))
s = append(s, ReceiptKeyPrefix...)
s = append(s, h...)
return string(s)
}
package chaindb
import (
"github.com/ethereum/go-ethereum/common"
"testing"
)
func benchmark(b *testing.B, f func(hash common.Hash) string) {
var h = common.HexToHash("0x4daf6f018bdc33e7f5548382a995b89a6eb809d09fdf386a750d10ed5b88b134")
for i := 0; i < b.N; i++ {
f(h)
}
}
func BenchmarkMemChaindb_TransactionKey1(b *testing.B) {
benchmark(b, transactionKey)
}
package genesis
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
// MarshalJSON marshals as JSON.
func (g *GenesisBlock) MarshalJSON() ([]byte, error) {
type Genesis struct {
ChainId uint64 `json:"chainId"`
Timestamp uint64 `json:"timestamp"`
ExtraData hexutil.Bytes `json:"extraData"`
Alloc map[string]GenesisAccount `json:"accounts"`
}
var enc Genesis
enc.Timestamp = g.Timestamp
enc.ExtraData = g.ExtraData
enc.ChainId = g.ChainId
if g.AllocInfo != nil {
enc.Alloc = make(map[string]GenesisAccount, len(g.AllocInfo))
for k, v := range g.AllocInfo {
enc.Alloc[k.String()] = v
}
}
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (g *GenesisBlock) UnmarshalJSON(input []byte) error {
type Genesis struct {
ChainId uint64 `json:"chainId"`
Timestamp uint64 `json:"timestamp"`
ExtraData *hexutil.Bytes `json:"extraData"`
Alloc map[common.Address]GenesisAccount `json:"accounts"`
}
var dec Genesis
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
g.Timestamp = dec.Timestamp
if dec.ExtraData != nil {
g.ExtraData = *dec.ExtraData
}
g.ChainId = dec.ChainId
if dec.Alloc == nil {
return errors.New("missing required field 'alloc' for Genesis")
}
g.AllocInfo = make(GenesisAlloc, len(dec.Alloc))
for k, v := range dec.Alloc {
g.AllocInfo[k] = v
}
return nil
}
package genesis
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common/hexutil"
"math/big"
)
// MarshalJSON marshals as JSON.
func (g GenesisAccount) MarshalJSON() ([]byte, error) {
type InnerWalletInfo struct {
Balance *hexutil.Big `json:"balance"`
Frozen *hexutil.Big `json:"frozen"`
}
type GenesisAccount struct {
SignerProxy *hexutil.Bytes `json:"signerProxy,omitempty"`
Assets map[string]InnerWalletInfo `json:"assets"`
}
var enc GenesisAccount
if len(g.SingerProxy) > 0 {
enc.SignerProxy = (*hexutil.Bytes)(&g.SingerProxy)
}
enc.Assets = make(map[string]InnerWalletInfo, len(g.Assets))
for k, v := range g.Assets {
wallet := InnerWalletInfo{}
if v.Balance != nil {
balance := hexutil.Big(*v.Balance)
wallet.Balance = &balance
}
if v.Frozen != nil {
frozen := hexutil.Big(*v.Frozen)
wallet.Frozen = &frozen
}
enc.Assets[k] = wallet
}
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (g *GenesisAccount) UnmarshalJSON(input []byte) error {
type InnerWalletInfo struct {
Balance *hexutil.Big `json:"balance"`
Frozen *hexutil.Big `json:"frozen"`
}
type GenesisAccount struct {
SignerProxy *hexutil.Bytes `json:"signerProxy,omitempty"`
Assets map[string]InnerWalletInfo `json:"assets"`
}
var dec GenesisAccount
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.SignerProxy != nil {
g.SingerProxy = *dec.SignerProxy
}
if dec.Assets != nil {
g.Assets = make(map[string]WalletInfo, len(dec.Assets))
for coin, v := range dec.Assets {
wallet := WalletInfo{}
if v.Balance != nil {
wallet.Balance = new(big.Int).Set(v.Balance.ToInt())
}
if v.Frozen != nil {
wallet.Frozen = new(big.Int).Set(v.Frozen.ToInt())
}
g.Assets[coin] = wallet
}
}
return nil
}
package genesis
import (
"encoding/json"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/exchain/go-exchain/exchain/chaindb"
nebulav1 "github.com/exchain/go-exchain/exchain/protocol/gen/go/nebula/v1"
"github.com/exchain/go-exchain/metadb"
"github.com/golang/protobuf/proto"
"github.com/holiman/uint256"
"math/big"
"os"
)
var (
genesisSigner = common.HexToAddress("0x5FbDB2315678afecb367f032d93F642f64180aa3")
genesisSignerKey, _ = crypto.HexToECDSA("329cb309edf3b9d0a5d16a16df6393da089f00f555a3290873a9daabc9e39711")
)
type WalletInfo struct {
Balance *big.Int `json:"balance"`
Frozen *big.Int `json:"frozen"`
}
type AssetsInfo map[string]WalletInfo
type GenesisAccount struct {
SingerProxy []byte `json:"signerProxy"`
Assets AssetsInfo `json:"assets"`
}
type GenesisBlock struct {
ChainId uint64 `json:"chainId"`
Timestamp uint64 `json:"timestamp"`
ExtraData []byte `json:"extraData"`
AllocInfo GenesisAlloc `json:"accounts"`
}
// GenesisAlloc specifies the initial state that is part of the genesis block.
type GenesisAlloc map[common.Address]GenesisAccount
func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
m := make(map[common.UnprefixedAddress]GenesisAccount)
if err := json.Unmarshal(data, &m); err != nil {
return err
}
*ga = make(GenesisAlloc)
for addr, a := range m {
(*ga)[common.Address(addr)] = a
}
return nil
}
func (g *GenesisBlock) Commit(db metadb.Database) (err error) {
chain := chaindb.NewChainDB(db)
blk := g.ToBlock()
return chain.SaveBlockData(blk, nil)
}
func (g *GenesisBlock) ToBlock() *nebulav1.Block {
blk := &nebulav1.Block{
Header: &nebulav1.BlockHeader{
Height: 0,
ParentHash: common.Hash{}.Bytes(),
Timestamp: g.Timestamp,
Proposer: genesisSigner.Bytes(),
L1Hash: common.Hash{}.Bytes(),
AppRoot: common.Hash{}.Bytes(),
},
Transactions: &nebulav1.TransactionList{},
}
hash := BlockHash(blk)
signature, _ := crypto.Sign(hash.Bytes(), genesisSignerKey)
blk.Header.Signatures = signature
blk.Header.Hash = hash.Bytes()
return blk
}
func (g *GenesisBlock) AddAccount(addr common.Address, account GenesisAccount) {
g.AllocInfo[addr] = account
}
func NewGenesisBlock(genfile string) (*GenesisBlock, error) {
data, err := os.ReadFile(genfile)
if err != nil {
return nil, err
}
var genblock GenesisBlock
err = json.Unmarshal(data, &genblock)
if err != nil {
return nil, err
}
return &genblock, nil
}
func BlockHash(blk *nebulav1.Block) common.Hash {
data := make([]byte, 0)
data = append(data, uint256.NewInt(blk.Header.Height).Bytes()...)
data = append(data, uint256.NewInt(blk.Header.Timestamp).Bytes()...)
data = append(data, blk.Header.ParentHash...)
data = append(data, blk.Header.L1Hash...)
data = append(data, blk.Header.AppRoot...)
data = append(data, blk.Header.Proposer...)
txdata, _ := proto.Marshal(blk.Transactions)
data = append(data, txdata...)
return crypto.Keccak256Hash(data)
}
func LoadGenesisAllocs(allocsPath string) (GenesisAlloc, error) {
f, err := os.OpenFile(allocsPath, os.O_RDONLY, 0644)
if err != nil {
return nil, fmt.Errorf("failed to open forge allocs %q: %w", allocsPath, err)
}
defer f.Close()
var out = make(GenesisAlloc)
if err := json.NewDecoder(f).Decode(out); err != nil {
return nil, fmt.Errorf("failed to json-decode forge allocs %q: %w", allocsPath, err)
}
return out, nil
}
{
"chainId": 10086,
"timestamp": 1676518132,
"extraData": "0x",
"accounts": {
"0x905D5E8F7db76bCA91fdcA0990be7263dfD23335": {
"signerProxy": "0x",
"assets": {
"usdc": {
"balance": "0x20000000000",
"frozen": "0x10"
}
}
}
}
}
package genesis
import (
"encoding/json"
"fmt"
"testing"
)
var testGenesis = `
{
"chainId": 10086,
"timestamp": 1676518132,
"extraData": "0x",
"accounts": {
"0x905D5E8F7db76bCA91fdcA0990be7263dfD23335": {
"signerProxy": "0x",
"assets": {
"usdc": {
"balance": "0x20000000000",
"frozen": "10"
}
}
}
}
}
`
func TestGenesis_UnmarshalJSON(t *testing.T) {
var gen GenesisBlock
err := json.Unmarshal([]byte(testGenesis), &gen)
if err != nil {
t.Fatal("unmarshal json failed", "err", err)
}
for addr, info := range gen.AllocInfo {
data, _ := info.MarshalJSON()
fmt.Printf("user[%s]={%s}\n", addr.String(), string(data))
}
}
func TestGenesis_MarshalJSON(t *testing.T) {
var gen GenesisBlock
err := json.Unmarshal([]byte(testGenesis), &gen)
if err != nil {
t.Fatal("unmarshal json failed", "err", err)
}
data, err := json.Marshal(gen)
if err != nil {
t.Fatal("marshal genesis block failed", "err", err)
}
fmt.Println("get genesis block marshal", string(data))
}
func TestGenesisBlock_ToBlock(t *testing.T) {
var gen GenesisBlock
err := json.Unmarshal([]byte(testGenesis), &gen)
if err != nil {
t.Fatal("unmarshal json failed", "err", err)
}
block := gen.ToBlock()
fmt.Println("genesis block is ", block.String())
}
package exchain
import (
"github.com/ethereum/go-ethereum/common"
nebulav1 "github.com/exchain/go-exchain/exchain/protocol/gen/go/nebula/v1"
)
// todo: define some structs here.
type ChainEvent struct {
Block *nebulav1.Block
BlockHash common.Hash
TxCount int64
}
......@@ -2,13 +2,12 @@ package genesis
import (
"errors"
"github.com/exchain/go-exchain/exchain/genesis"
"math/big"
"time"
"github.com/exchain/go-exchain/op-service/predeploys"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
......@@ -17,104 +16,25 @@ import (
// defaultGasLimit represents the default gas limit for a genesis block.
const defaultGasLimit = 30_000_000
// HoloceneExtraData represents the default extra data for Holocene-genesis chains.
var HoloceneExtraData = eip1559.EncodeHoloceneExtraData(250, 6)
// NewL2Genesis will create a new L2 genesis
func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*core.Genesis, error) {
func NewL2Genesis(config *DeployConfig, l1StartHeader *types.Header) (*genesis.GenesisBlock, error) {
if config.L2ChainID == 0 {
return nil, errors.New("must define L2 ChainID")
}
eip1559Denom := config.EIP1559Denominator
if eip1559Denom == 0 {
eip1559Denom = 50
}
eip1559DenomCanyon := config.EIP1559DenominatorCanyon
if eip1559DenomCanyon == 0 {
eip1559DenomCanyon = 250
}
eip1559Elasticity := config.EIP1559Elasticity
if eip1559Elasticity == 0 {
eip1559Elasticity = 10
}
l1StartTime := l1StartHeader.Time
optimismChainConfig := params.ChainConfig{
ChainID: new(big.Int).SetUint64(config.L2ChainID),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0),
TerminalTotalDifficulty: big.NewInt(0),
BedrockBlock: new(big.Int).SetUint64(uint64(config.L2GenesisBlockNumber)),
RegolithTime: config.RegolithTime(l1StartTime),
CanyonTime: config.CanyonTime(l1StartTime),
ShanghaiTime: config.CanyonTime(l1StartTime),
CancunTime: config.EcotoneTime(l1StartTime),
EcotoneTime: config.EcotoneTime(l1StartTime),
FjordTime: config.FjordTime(l1StartTime),
GraniteTime: config.GraniteTime(l1StartTime),
HoloceneTime: config.HoloceneTime(l1StartTime),
IsthmusTime: config.IsthmusTime(l1StartTime),
InteropTime: config.InteropTime(l1StartTime),
Optimism: &params.OptimismConfig{
EIP1559Denominator: eip1559Denom,
EIP1559Elasticity: eip1559Elasticity,
EIP1559DenominatorCanyon: &eip1559DenomCanyon,
},
}
gasLimit := config.L2GenesisBlockGasLimit
if gasLimit == 0 {
gasLimit = defaultGasLimit
}
baseFee := config.L2GenesisBlockBaseFeePerGas
if baseFee == nil {
baseFee = newHexBig(params.InitialBaseFee)
}
difficulty := config.L2GenesisBlockDifficulty
if difficulty == nil {
difficulty = newHexBig(0)
}
genesis := &core.Genesis{
Config: &optimismChainConfig,
Nonce: uint64(config.L2GenesisBlockNonce),
blk := &genesis.GenesisBlock{
ChainId: config.L2ChainID,
Timestamp: l1StartTime,
GasLimit: uint64(gasLimit),
Difficulty: difficulty.ToInt(),
Mixhash: config.L2GenesisBlockMixHash,
Coinbase: predeploys.SequencerFeeVaultAddr,
Number: uint64(config.L2GenesisBlockNumber),
GasUsed: uint64(config.L2GenesisBlockGasUsed),
ParentHash: config.L2GenesisBlockParentHash,
BaseFee: baseFee.ToInt(),
Alloc: map[common.Address]types.Account{},
}
if optimismChainConfig.IsEcotone(genesis.Timestamp) {
genesis.BlobGasUsed = u64ptr(0)
genesis.ExcessBlobGas = u64ptr(0)
}
if optimismChainConfig.IsHolocene(genesis.Timestamp) {
genesis.ExtraData = HoloceneExtraData
AllocInfo: make(genesis.GenesisAlloc),
}
return genesis, nil
return blk, nil
}
// NewL1Genesis will create a new L1 genesis config
......
package genesis
import (
"fmt"
"math/big"
hdwallet "github.com/ethereum-optimism/go-ethereum-hdwallet"
"github.com/holiman/uint256"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/exchain/go-exchain/exchain/genesis"
"github.com/exchain/go-exchain/op-chain-ops/foundry"
"github.com/exchain/go-exchain/op-service/predeploys"
)
type L2AllocsMode string
......@@ -40,61 +31,12 @@ var (
type AllocsLoader func(mode L2AllocsMode) *foundry.ForgeAllocs
// BuildL2Genesis will build the L2 genesis block.
func BuildL2Genesis(config *DeployConfig, dump *foundry.ForgeAllocs, l1StartBlock *types.Header) (*core.Genesis, error) {
func BuildL2Genesis(config *DeployConfig, dump genesis.GenesisAlloc, l1StartBlock *types.Header) (*genesis.GenesisBlock, error) {
genspec, err := NewL2Genesis(config, l1StartBlock)
if err != nil {
return nil, err
}
genspec.Alloc = dump.Copy().Accounts
// ensure the dev accounts are not funded unintentionally
if devAccounts, err := RetrieveDevAccounts(genspec.Alloc); err != nil {
return nil, fmt.Errorf("failed to check dev accounts: %w", err)
} else if (len(devAccounts) > 0) != config.FundDevAccounts {
return nil, fmt.Errorf("deploy config mismatch with allocs. Deploy config fundDevAccounts: %v, actual allocs: %v", config.FundDevAccounts, devAccounts)
}
// sanity check the permit2 immutable, to verify we using the allocs for the right chain.
if permit2 := genspec.Alloc[predeploys.Permit2Addr].Code; len(permit2) != 0 {
if len(permit2) < 6945+32 {
return nil, fmt.Errorf("permit2 code is too short (%d)", len(permit2))
}
chainID := [32]byte(permit2[6945 : 6945+32])
expected := uint256.MustFromBig(genspec.Config.ChainID).Bytes32()
if chainID != expected {
return nil, fmt.Errorf("allocs were generated for chain ID %x, but expected chain %x (%d)", chainID, expected, genspec.Config.ChainID)
}
}
// sanity check that all predeploys are present
for i := 0; i < 2048; i++ {
addr := common.BigToAddress(new(big.Int).Or(l2PredeployNamespace.Big(), big.NewInt(int64(i))))
if !config.GovernanceEnabled() && addr == predeploys.GovernanceTokenAddr {
continue
}
if len(genspec.Alloc[addr].Code) == 0 {
return nil, fmt.Errorf("predeploy %x is missing from L2 genesis allocs", addr)
}
}
genspec.AllocInfo = dump
return genspec, nil
}
func RetrieveDevAccounts(allocs types.GenesisAlloc) ([]common.Address, error) {
wallet, err := hdwallet.NewFromMnemonic(testMnemonic)
if err != nil {
return nil, fmt.Errorf("failed to create wallet: %w", err)
}
account := func(path string) accounts.Account {
return accounts.Account{URL: accounts.URL{Path: path}}
}
var devAccounts []common.Address
for i := 0; i < 30; i++ {
key, err := wallet.PrivateKey(account(fmt.Sprintf("m/44'/60'/0'/0/%d", i)))
if err != nil {
return nil, err
}
addr := crypto.PubkeyToAddress(key.PublicKey)
if _, ok := allocs[addr]; ok {
devAccounts = append(devAccounts, addr)
}
}
return devAccounts, nil
}
......@@ -320,10 +320,11 @@ func CompleteL2(l2Host *script.Host, cfg *L2Config, l1Block *types.Block, deploy
allocs.Accounts[addr] = acc
}
l2Genesis.Alloc = allocs.Accounts
// todo: vicotor add the allocs to the genesis block.
//l2Genesis.AllocInfo = allocs.Accounts
l2GenesisBlock := l2Genesis.ToBlock()
rollupCfg, err := deployCfg.RollupConfig(l1Block.Header(), l2GenesisBlock.Hash(), l2GenesisBlock.NumberU64())
rollupCfg, err := deployCfg.RollupConfig(l1Block.Header(), common.BytesToHash(l2GenesisBlock.Header.Hash), l2GenesisBlock.Header.Height)
if err != nil {
return nil, fmt.Errorf("failed to build L2 rollup config: %w", err)
}
......
......@@ -2,6 +2,7 @@ package interopgen
import (
"github.com/ethereum/go-ethereum/core"
"github.com/exchain/go-exchain/exchain/genesis"
"github.com/exchain/go-exchain/op-node/rollup"
)
......@@ -11,7 +12,7 @@ type L1Output struct {
}
type L2Output struct {
Genesis *core.Genesis
Genesis *genesis.GenesisBlock
RollupCfg *rollup.Config
}
......
......@@ -3,6 +3,9 @@ package genesis
import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/common"
chaingenesis "github.com/exchain/go-exchain/exchain/genesis"
"github.com/exchain/go-exchain/metadb/groupdb"
"time"
"github.com/exchain/go-exchain/op-service/ioutil"
......@@ -10,12 +13,12 @@ import (
"github.com/exchain/go-exchain/op-service/sources/batching"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/exchain/go-exchain/op-chain-ops/foundry"
"github.com/exchain/go-exchain/op-chain-ops/genesis"
"github.com/exchain/go-exchain/op-service/jsonutil"
oplog "github.com/exchain/go-exchain/op-service/log"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)
var (
......@@ -42,6 +45,15 @@ var (
Name: "outfile.rollup",
Usage: "Path to rollup output file",
}
genesisFileFlag = &cli.PathFlag{
Name: "genesis",
Usage: "Path to L2 genesis file",
}
dataDirFlag = &cli.PathFlag{
Name: "data-dir",
Usage: "Path to the directory where the node will store its data",
Value: "node",
}
l1AllocsFlag = &cli.StringFlag{
Name: "l1-allocs",
......@@ -71,6 +83,10 @@ var (
outfileL2Flag,
outfileRollupFlag,
}
initFlags = []cli.Flag{
genesisFileFlag,
dataDirFlag,
}
)
var Subcommands = cli.Commands{
......@@ -153,9 +169,9 @@ var Subcommands = cli.Commands{
}
config.SetDeployments(deployments)
var l2Allocs *foundry.ForgeAllocs
var l2Allocs chaingenesis.GenesisAlloc
if l2AllocsPath := ctx.String(l2AllocsFlag.Name); l2AllocsPath != "" {
l2Allocs, err = foundry.LoadForgeAllocs(l2AllocsPath)
l2Allocs, err = chaingenesis.LoadGenesisAllocs(l2AllocsPath)
if err != nil {
return err
}
......@@ -197,7 +213,7 @@ var Subcommands = cli.Commands{
}
l2GenesisBlock := l2Genesis.ToBlock()
rollupConfig, err := config.RollupConfig(l1StartBlock.Header(), l2GenesisBlock.Hash(), l2GenesisBlock.Number().Uint64())
rollupConfig, err := config.RollupConfig(l1StartBlock.Header(), common.BytesToHash(l2GenesisBlock.Header.Hash), l2GenesisBlock.Header.Height)
if err != nil {
return err
}
......@@ -211,4 +227,32 @@ var Subcommands = cli.Commands{
return jsonutil.WriteJSON(rollupConfig, ioutil.ToAtomicFile(ctx.String(outfileRollupFlag.Name), 0o666))
},
},
{
Name: "init",
Usage: "Init the L2 chain with the genesis.json",
Description: "Generating the L2 genesis block with genesis.json and write it to node data.",
Flags: initFlags,
Action: func(ctx *cli.Context) error {
cfg := oplog.DefaultCLIConfig()
logger := oplog.NewLogger(ctx.App.Writer, cfg)
genesisFile := ctx.Path(genesisFileFlag.Name)
dataDir := ctx.Path(dataDirFlag.Name)
logger.Info("Genesis file", "path", genesisFile)
logger.Info("Data directory", "path", dataDir)
database := groupdb.NewGroupDB(dataDir, "chain")
genblk, err := chaingenesis.NewGenesisBlock(genesisFile)
if err != nil {
logger.Error("Failed to create genesis block", "err", err)
return err
}
if err = genblk.Commit(database); err != nil {
logger.Error("Failed to commit genesis block", "err", err)
}
// wait db write to disk.
time.Sleep(2 * time.Second)
return nil
},
},
}
......@@ -6,9 +6,11 @@ import (
"fmt"
"github.com/exchain/go-exchain/engine"
"github.com/exchain/go-exchain/exchain"
"github.com/exchain/go-exchain/exchain/chaindb"
"github.com/exchain/go-exchain/exchain/mockengine"
"github.com/exchain/go-exchain/metadb"
"github.com/exchain/go-exchain/metadb/groupdb"
"github.com/holiman/uint256"
"io"
gosync "sync"
"sync/atomic"
......@@ -67,7 +69,7 @@ type OpNode struct {
l1Source *sources.L1Client // L1 Client to fetch data from
l2Driver *driver.Driver // L2 Engine to Sync
//l2Source *sources.EngineClient // L2 Execution Engine RPC bindings
l2Source *engine.EngineAPI // L2 Execution Engine RPC bindings
l2Source *engine.ExChainAPI // L2 Execution Engine RPC bindings
server *rpcServer // RPC server hosting the rollup-node API
p2pNode *p2p.NodeP2P // P2P node functionality
p2pMu gosync.Mutex // protects p2pNode
......@@ -396,11 +398,18 @@ func (n *OpNode) initL1BeaconAPI(ctx context.Context, cfg *Config) error {
func (n *OpNode) initL2(ctx context.Context, cfg *Config) error {
var err error
n.db = groupdb.NewGroupDB(n.cfg.NodeDataPath, "engine")
chain := chaindb.NewChainDB(n.db)
n.engineIns = mockengine.NewEngine(n.db)
n.l2Source = engine.NewEngineAPI(n.db)
n.l2Source = engine.NewEngineAPI(chain)
if n.engineIns == nil {
return errors.New("failed to create L2 engine")
}
// check genesis block.
if blk := chain.GetBlock(uint256.NewInt(0)); blk == nil {
return fmt.Errorf("node is not initialized, missing genesis block")
}
if err = n.engineIns.Start(); err != nil {
return fmt.Errorf("failed to start L2 engine: %w", err)
}
......
package grouptask
import (
"errors"
"sync"
)
var (
ErrTaskPoolIsFull = errors.New("task pool is full")
)
type TaskHandle func(interface{}, uint)
type Tasks struct {
tasknum uint
handler TaskHandle
taskpool chan interface{}
wg sync.WaitGroup
}
func NewTasks(routine uint, handle TaskHandle) *Tasks {
return &Tasks{
tasknum: routine,
handler: handle,
taskpool: make(chan interface{}, 1000000),
}
}
func (t *Tasks) AddTask(task interface{}) error {
select {
case t.taskpool <- task:
return nil
default:
return ErrTaskPoolIsFull
}
}
func (t *Tasks) WaitFinish() {
close(t.taskpool)
t.wg.Wait()
}
func (t *Tasks) Run() {
for i := uint(0); i < t.tasknum; i++ {
t.wg.Add(1)
go func(chanIdx uint) {
defer t.wg.Done()
for {
select {
case task, ok := <-t.taskpool:
if !ok {
return
}
t.handler(task, chanIdx)
}
}
}(i)
}
}
func DoMultiTasks(routine int, handler TaskHandle, items ...interface{}) {
tasks := NewTasks(uint(routine), handler)
tasks.Run()
for _, item := range items {
tasks.AddTask(item)
}
tasks.WaitFinish()
}
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