github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/test/operations/manager.go (about)

     1  package operations
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/big"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/0xPolygon/supernets2-node/db"
    14  	"github.com/0xPolygon/supernets2-node/event"
    15  	"github.com/0xPolygon/supernets2-node/event/nileventstorage"
    16  	"github.com/0xPolygon/supernets2-node/log"
    17  	"github.com/0xPolygon/supernets2-node/merkletree"
    18  	"github.com/0xPolygon/supernets2-node/state"
    19  	"github.com/0xPolygon/supernets2-node/state/runtime/executor"
    20  	"github.com/0xPolygon/supernets2-node/test/constants"
    21  	"github.com/0xPolygon/supernets2-node/test/dbutils"
    22  	"github.com/0xPolygon/supernets2-node/test/testutils"
    23  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    24  	"github.com/ethereum/go-ethereum/core/types"
    25  	"github.com/ethereum/go-ethereum/crypto"
    26  	"github.com/ethereum/go-ethereum/ethclient"
    27  )
    28  
    29  const (
    30  	cmdFolder = "test"
    31  )
    32  
    33  // Public shared
    34  const (
    35  	DefaultSequencerAddress                 = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
    36  	DefaultSequencerPrivateKey              = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
    37  	DefaultSequencerBalance                 = 400000
    38  	DefaultMaxCumulativeGasUsed             = 800000
    39  	DefaultL1Supernets2SmartContract        = "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82"
    40  	DefaultL1DataCommitteeContract          = "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6"
    41  	DefaultL1NetworkURL                     = "http://localhost:8545"
    42  	DefaultL1NetworkWebSocketURL            = "ws://localhost:8546"
    43  	DefaultL1ChainID                 uint64 = 1337
    44  
    45  	DefaultL2NetworkURL                 = "http://localhost:8123"
    46  	PermissionlessL2NetworkURL          = "http://localhost:8125"
    47  	DefaultL2NetworkWebSocketURL        = "ws://localhost:8133"
    48  	DefaultL2ChainID             uint64 = 1001
    49  
    50  	DefaultTimeoutTxToBeMined = 1 * time.Minute
    51  
    52  	DefaultWaitPeriodSendSequence                          = "15s"
    53  	DefaultLastBatchVirtualizationTimeMaxWaitPeriod        = "10s"
    54  	MaxBatchesForL1                                 uint64 = 1
    55  )
    56  
    57  var (
    58  	stateDBCfg = dbutils.NewStateConfigFromEnv()
    59  	poolDBCfg  = dbutils.NewPoolConfigFromEnv()
    60  
    61  	executorURI      = testutils.GetEnv(constants.ENV_ZKPROVER_URI, "127.0.0.1:50071")
    62  	merkleTreeURI    = testutils.GetEnv(constants.ENV_MERKLETREE_URI, "127.0.0.1:50061")
    63  	executorConfig   = executor.Config{URI: executorURI}
    64  	merkleTreeConfig = merkletree.Config{URI: merkleTreeURI}
    65  )
    66  
    67  // SequenceSenderConfig is the configuration for the sequence sender operations
    68  type SequenceSenderConfig struct {
    69  	WaitPeriodSendSequence                   string
    70  	LastBatchVirtualizationTimeMaxWaitPeriod string
    71  	MaxBatchesForL1                          uint64
    72  	SenderAddress                            string
    73  	PrivateKey                               string
    74  }
    75  
    76  // Config is the main Manager configuration.
    77  type Config struct {
    78  	State          *state.Config
    79  	SequenceSender *SequenceSenderConfig
    80  }
    81  
    82  // Manager controls operations and has knowledge about how to set up and tear
    83  // down a functional environment.
    84  type Manager struct {
    85  	cfg *Config
    86  	ctx context.Context
    87  
    88  	st   *state.State
    89  	wait *Wait
    90  }
    91  
    92  // NewManager returns a manager ready to be used and a potential error caused
    93  // during its creation (which can come from the setup of the db connection).
    94  func NewManager(ctx context.Context, cfg *Config) (*Manager, error) {
    95  	// Init database instance
    96  	initOrResetDB()
    97  
    98  	opsman := &Manager{
    99  		cfg:  cfg,
   100  		ctx:  ctx,
   101  		wait: NewWait(),
   102  	}
   103  	st, err := initState(cfg.State.MaxCumulativeGasUsed)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	opsman.st = st
   108  
   109  	return opsman, nil
   110  }
   111  
   112  // State is a getter for the st field.
   113  func (m *Manager) State() *state.State {
   114  	return m.st
   115  }
   116  
   117  // CheckVirtualRoot verifies if the given root is the current root of the
   118  // merkletree for virtual state.
   119  func (m *Manager) CheckVirtualRoot(expectedRoot string) error {
   120  	panic("not implemented yet")
   121  	// root, err := m.st.Getroot(m.ctx, true, "")
   122  	// if err != nil {
   123  	// 	return err
   124  	// }
   125  	// return m.checkRoot(root, expectedRoot)
   126  }
   127  
   128  // CheckConsolidatedRoot verifies if the given root is the current root of the
   129  // merkletree for consolidated state.
   130  func (m *Manager) CheckConsolidatedRoot(expectedRoot string) error {
   131  	panic("not implemented yet")
   132  	// root, err := m.st.GetStateRoot(m.ctx, false, "")
   133  	// if err != nil {
   134  	// 	return err
   135  	// }
   136  	// return m.checkRoot(root, expectedRoot)
   137  }
   138  
   139  // SetGenesisAccountsBalance creates the genesis block in the state.
   140  func (m *Manager) SetGenesisAccountsBalance(genesisAccounts map[string]big.Int) error {
   141  	var genesisActions []*state.GenesisAction
   142  	for address, balanceValue := range genesisAccounts {
   143  		action := &state.GenesisAction{
   144  			Address: address,
   145  			Type:    int(merkletree.LeafTypeBalance),
   146  			Value:   balanceValue.String(),
   147  		}
   148  		genesisActions = append(genesisActions, action)
   149  	}
   150  
   151  	return m.SetGenesis(genesisActions)
   152  }
   153  
   154  func (m *Manager) SetGenesis(genesisActions []*state.GenesisAction) error {
   155  	genesisBlock := state.Block{
   156  		BlockNumber: 0,
   157  		BlockHash:   state.ZeroHash,
   158  		ParentHash:  state.ZeroHash,
   159  		ReceivedAt:  time.Now(),
   160  	}
   161  	genesis := state.Genesis{
   162  		GenesisActions: genesisActions,
   163  	}
   164  
   165  	dbTx, err := m.st.BeginStateTransaction(m.ctx)
   166  	if err != nil {
   167  		return err
   168  	}
   169  
   170  	_, err = m.st.SetGenesis(m.ctx, genesisBlock, genesis, dbTx)
   171  
   172  	err = dbTx.Commit(m.ctx)
   173  	if err != nil {
   174  		return err
   175  	}
   176  
   177  	return err
   178  }
   179  
   180  // ApplyL1Txs sends the given L1 txs, waits for them to be consolidated and
   181  // checks the final state.
   182  func ApplyL1Txs(ctx context.Context, txs []*types.Transaction, auth *bind.TransactOpts, client *ethclient.Client) error {
   183  	_, err := applyTxs(ctx, txs, auth, client, true)
   184  	return err
   185  }
   186  
   187  // ConfirmationLevel type used to describe the confirmation level of a transaction
   188  type ConfirmationLevel int
   189  
   190  // PoolConfirmationLevel indicates that transaction is added into the pool
   191  const PoolConfirmationLevel ConfirmationLevel = 0
   192  
   193  // TrustedConfirmationLevel indicates that transaction is  added into the trusted state
   194  const TrustedConfirmationLevel ConfirmationLevel = 1
   195  
   196  // VirtualConfirmationLevel indicates that transaction is  added into the virtual state
   197  const VirtualConfirmationLevel ConfirmationLevel = 2
   198  
   199  // VerifiedConfirmationLevel indicates that transaction is  added into the verified state
   200  const VerifiedConfirmationLevel ConfirmationLevel = 3
   201  
   202  // ApplyL2Txs sends the given L2 txs, waits for them to be consolidated and
   203  // checks the final state.
   204  func ApplyL2Txs(ctx context.Context, txs []*types.Transaction, auth *bind.TransactOpts, client *ethclient.Client, confirmationLevel ConfirmationLevel) ([]*big.Int, error) {
   205  	var err error
   206  	if auth == nil {
   207  		auth, err = GetAuth(DefaultSequencerPrivateKey, DefaultL2ChainID)
   208  		if err != nil {
   209  			return nil, err
   210  		}
   211  	}
   212  
   213  	if client == nil {
   214  		client, err = ethclient.Dial(DefaultL2NetworkURL)
   215  		if err != nil {
   216  			return nil, err
   217  		}
   218  	}
   219  	waitToBeMined := confirmationLevel != PoolConfirmationLevel
   220  	var initialNonce uint64
   221  	if waitToBeMined {
   222  		initialNonce, err = client.NonceAt(ctx, auth.From, nil)
   223  		if err != nil {
   224  			return nil, err
   225  		}
   226  	}
   227  	sentTxs, err := applyTxs(ctx, txs, auth, client, waitToBeMined)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	if confirmationLevel == PoolConfirmationLevel {
   232  		return nil, nil
   233  	}
   234  
   235  	l2BlockNumbers := make([]*big.Int, 0, len(sentTxs))
   236  	for i, tx := range sentTxs {
   237  		// check transaction nonce against transaction reported L2 block number
   238  		receipt, err := client.TransactionReceipt(ctx, tx.Hash())
   239  		if err != nil {
   240  			return nil, err
   241  		}
   242  
   243  		// get L2 block number
   244  		l2BlockNumbers = append(l2BlockNumbers, receipt.BlockNumber)
   245  		expectedNonce := initialNonce + uint64(i)
   246  		if tx.Nonce() != expectedNonce {
   247  			return nil, fmt.Errorf("mismatching nonce for tx %v: want %d, got %d\n", tx.Hash(), expectedNonce, tx.Nonce())
   248  		}
   249  		if confirmationLevel == TrustedConfirmationLevel {
   250  			continue
   251  		}
   252  
   253  		// wait for l2 block to be virtualized
   254  		log.Infof("waiting for the block number %v to be virtualized", receipt.BlockNumber.String())
   255  		err = WaitL2BlockToBeVirtualized(receipt.BlockNumber, 4*time.Minute) //nolint:gomnd
   256  		if err != nil {
   257  			return nil, err
   258  		}
   259  		if confirmationLevel == VirtualConfirmationLevel {
   260  			continue
   261  		}
   262  
   263  		// wait for l2 block number to be consolidated
   264  		log.Infof("waiting for the block number %v to be consolidated", receipt.BlockNumber.String())
   265  		err = WaitL2BlockToBeConsolidated(receipt.BlockNumber, 4*time.Minute) //nolint:gomnd
   266  		if err != nil {
   267  			return nil, err
   268  		}
   269  	}
   270  
   271  	return l2BlockNumbers, nil
   272  }
   273  
   274  func applyTxs(ctx context.Context, txs []*types.Transaction, auth *bind.TransactOpts, client *ethclient.Client, waitToBeMined bool) ([]*types.Transaction, error) {
   275  	var sentTxs []*types.Transaction
   276  
   277  	for i := 0; i < len(txs); i++ {
   278  		signedTx, err := auth.Signer(auth.From, txs[i])
   279  		if err != nil {
   280  			return nil, err
   281  		}
   282  		log.Infof("Sending Tx %v Nonce %v", signedTx.Hash(), signedTx.Nonce())
   283  		err = client.SendTransaction(context.Background(), signedTx)
   284  		if err != nil {
   285  			return nil, err
   286  		}
   287  
   288  		sentTxs = append(sentTxs, signedTx)
   289  	}
   290  	if !waitToBeMined {
   291  		return nil, nil
   292  	}
   293  
   294  	// wait for TX to be mined
   295  	timeout := 180 * time.Second //nolint:gomnd
   296  	for _, tx := range sentTxs {
   297  		log.Infof("Waiting Tx %s to be mined", tx.Hash())
   298  		err := WaitTxToBeMined(ctx, client, tx, timeout)
   299  		if err != nil {
   300  			return nil, err
   301  		}
   302  		log.Infof("Tx %s mined successfully", tx.Hash())
   303  	}
   304  	nTxs := len(txs)
   305  	if nTxs > 1 {
   306  		log.Infof("%d transactions added into the trusted state successfully.", nTxs)
   307  	} else {
   308  		log.Info("transaction added into the trusted state successfully.")
   309  	}
   310  
   311  	return sentTxs, nil
   312  }
   313  
   314  // GetAuth configures and returns an auth object.
   315  func GetAuth(privateKeyStr string, chainID uint64) (*bind.TransactOpts, error) {
   316  	privateKey, err := crypto.HexToECDSA(strings.TrimPrefix(privateKeyStr, "0x"))
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  
   321  	return bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(0).SetUint64(chainID))
   322  }
   323  
   324  // MustGetAuth GetAuth but panics if err
   325  func MustGetAuth(privateKeyStr string, chainID uint64) *bind.TransactOpts {
   326  	auth, err := GetAuth(privateKeyStr, chainID)
   327  	if err != nil {
   328  		panic(err)
   329  	}
   330  	return auth
   331  }
   332  
   333  // Setup creates all the required components and initializes them according to
   334  // the manager config.
   335  func (m *Manager) Setup() error {
   336  	// Run network container
   337  	err := m.StartNetwork()
   338  	if err != nil {
   339  		return err
   340  	}
   341  
   342  	// Approve matic
   343  	err = ApproveMatic()
   344  	if err != nil {
   345  		return err
   346  	}
   347  
   348  	// Run node container
   349  	err = m.StartNode()
   350  	if err != nil {
   351  		return err
   352  	}
   353  
   354  	return nil
   355  }
   356  
   357  // SetupWithPermissionless creates all the required components for both trusted and permissionless nodes
   358  // and initializes them according to the manager config.
   359  func (m *Manager) SetupWithPermissionless() error {
   360  	// Run network container
   361  	err := m.StartNetwork()
   362  	if err != nil {
   363  		return err
   364  	}
   365  
   366  	// Approve matic
   367  	err = ApproveMatic()
   368  	if err != nil {
   369  		return err
   370  	}
   371  
   372  	err = m.StartTrustedAndPermissionlessNode()
   373  	if err != nil {
   374  		return err
   375  	}
   376  
   377  	// Run node container
   378  	return nil
   379  }
   380  
   381  // StartEthTxSender stops the eth tx sender service
   382  func (m *Manager) StartEthTxSender() error {
   383  	return StartComponent("eth-tx-manager")
   384  }
   385  
   386  // StopEthTxSender stops the eth tx sender service
   387  func (m *Manager) StopEthTxSender() error {
   388  	return StopComponent("eth-tx-manager")
   389  }
   390  
   391  // StartSequencer starts the sequencer
   392  func (m *Manager) StartSequencer() error {
   393  	return StartComponent("seq")
   394  }
   395  
   396  // StopSequencer stops the sequencer
   397  func (m *Manager) StopSequencer() error {
   398  	return StopComponent("seq")
   399  }
   400  
   401  // StartSequenceSender starts the sequence sender
   402  func (m *Manager) StartSequenceSender() error {
   403  	return StartComponent("seqsender")
   404  }
   405  
   406  // StopSequenceSender stops the sequence sender
   407  func (m *Manager) StopSequenceSender() error {
   408  	return StopComponent("seqsender")
   409  }
   410  
   411  // Teardown stops all the components.
   412  func Teardown() error {
   413  	err := stopNode()
   414  	if err != nil {
   415  		return err
   416  	}
   417  
   418  	err = stopNetwork()
   419  	if err != nil {
   420  		return err
   421  	}
   422  
   423  	return nil
   424  }
   425  
   426  // TeardownPermissionless stops all the components.
   427  func TeardownPermissionless() error {
   428  	err := stopPermissionlessNode()
   429  	if err != nil {
   430  		return err
   431  	}
   432  
   433  	err = stopNetwork()
   434  	if err != nil {
   435  		return err
   436  	}
   437  
   438  	return nil
   439  }
   440  
   441  func initState(maxCumulativeGasUsed uint64) (*state.State, error) {
   442  	sqlDB, err := db.NewSQLDB(stateDBCfg)
   443  	if err != nil {
   444  		return nil, err
   445  	}
   446  
   447  	ctx := context.Background()
   448  	stateDb := state.NewPostgresStorage(sqlDB)
   449  	executorClient, _, _ := executor.NewExecutorClient(ctx, executorConfig)
   450  	stateDBClient, _, _ := merkletree.NewMTDBServiceClient(ctx, merkleTreeConfig)
   451  	stateTree := merkletree.NewStateTree(stateDBClient)
   452  
   453  	stateCfg := state.Config{
   454  		MaxCumulativeGasUsed: maxCumulativeGasUsed,
   455  	}
   456  
   457  	eventStorage, err := nileventstorage.NewNilEventStorage()
   458  	if err != nil {
   459  		return nil, err
   460  	}
   461  	eventLog := event.NewEventLog(event.Config{}, eventStorage)
   462  
   463  	st := state.NewState(stateCfg, stateDb, executorClient, stateTree, eventLog)
   464  	return st, nil
   465  }
   466  
   467  // StartNetwork starts the L1 network container
   468  func (m *Manager) StartNetwork() error {
   469  	return StartComponent("network", networkUpCondition)
   470  }
   471  
   472  // InitNetwork Initializes the L2 network registering the sequencer and adding funds via the bridge
   473  func (m *Manager) InitNetwork() error {
   474  	if err := RunMakeTarget("init-network"); err != nil {
   475  		return err
   476  	}
   477  
   478  	// Wait network to be ready
   479  	return Poll(DefaultInterval, DefaultDeadline, networkUpCondition)
   480  }
   481  
   482  // DeployUniswap deploys a uniswap environment and perform swaps
   483  func (m *Manager) DeployUniswap() error {
   484  	if err := RunMakeTarget("deploy-uniswap"); err != nil {
   485  		return err
   486  	}
   487  	// Wait network to be ready
   488  	return Poll(DefaultInterval, DefaultDeadline, networkUpCondition)
   489  }
   490  
   491  func stopNetwork() error {
   492  	return StopComponent("network")
   493  }
   494  
   495  // StartNode starts the node container
   496  func (m *Manager) StartNode() error {
   497  	return StartComponent("node", nodeUpCondition)
   498  }
   499  
   500  // StartTrustedAndPermissionlessNode starts the node container
   501  func (m *Manager) StartTrustedAndPermissionlessNode() error {
   502  	return StartComponent("permissionless", nodeUpCondition)
   503  }
   504  
   505  // StartDACDB starts the data availability node DB
   506  func (m *Manager) StartDACDB() error {
   507  	return StartComponent("dac-db", func() (bool, error) { return true, nil })
   508  }
   509  
   510  // StopDACDB stops the data availability node DB
   511  func (m *Manager) StopDACDB() error {
   512  	return StopComponent("dac-db")
   513  }
   514  
   515  // StartPermissionlessNodeForcedToSYncThroughDAC starts a permissionless node that is froced to sync through the DAC
   516  func (m *Manager) StartPermissionlessNodeForcedToSYncThroughDAC() error {
   517  	return StartComponent("permissionless-dac", func() (bool, error) { return true, nil })
   518  }
   519  
   520  // StopPermissionlessNodeForcedToSYncThroughDAC stops the permissionless node that is froced to sync through the DAC
   521  func (m *Manager) StopPermissionlessNodeForcedToSYncThroughDAC() error {
   522  	return StopComponent("permissionless-dac")
   523  }
   524  
   525  // ApproveMatic runs the approving matic command
   526  func ApproveMatic() error {
   527  	return StartComponent("approve-matic")
   528  }
   529  
   530  func stopNode() error {
   531  	return StopComponent("node")
   532  }
   533  
   534  func stopPermissionlessNode() error {
   535  	return StopComponent("permissionless")
   536  }
   537  
   538  func runCmd(c *exec.Cmd) error {
   539  	dir, err := os.Getwd()
   540  	if err != nil {
   541  		log.Fatalf("failed to get current work directory: %v", err)
   542  	}
   543  
   544  	if strings.Contains(dir, cmdFolder) {
   545  		// Making the change dir to work in any nesting directory level inside cmd folder
   546  		base := filepath.Base(dir)
   547  		for base != cmdFolder {
   548  			dir = filepath.Dir(dir)
   549  			base = filepath.Base(dir)
   550  		}
   551  	} else {
   552  		dir = fmt.Sprintf("../../%s", cmdFolder)
   553  	}
   554  	c.Dir = dir
   555  
   556  	c.Stdout = os.Stdout
   557  	c.Stderr = os.Stderr
   558  	return c.Run()
   559  }
   560  
   561  // StartComponent starts a docker-compose component.
   562  func StartComponent(component string, conditions ...ConditionFunc) error {
   563  	cmdDown := fmt.Sprintf("stop-%s", component)
   564  	if err := RunMakeTarget(cmdDown); err != nil {
   565  		return err
   566  	}
   567  	cmdUp := fmt.Sprintf("run-%s", component)
   568  	if err := RunMakeTarget(cmdUp); err != nil {
   569  		return err
   570  	}
   571  
   572  	// Wait component to be ready
   573  	for _, condition := range conditions {
   574  		if err := Poll(DefaultInterval, DefaultDeadline, condition); err != nil {
   575  			return err
   576  		}
   577  	}
   578  	return nil
   579  }
   580  
   581  // StopComponent stops a docker-compose component.
   582  func StopComponent(component string) error {
   583  	cmdDown := fmt.Sprintf("stop-%s", component)
   584  	return RunMakeTarget(cmdDown)
   585  }
   586  
   587  // RunMakeTarget runs a Makefile target.
   588  func RunMakeTarget(target string) error {
   589  	cmd := exec.Command("make", target)
   590  	return runCmd(cmd)
   591  }
   592  
   593  // GetDefaultOperationsConfig provides a default configuration to run the environment
   594  func GetDefaultOperationsConfig() *Config {
   595  	return &Config{
   596  		State: &state.Config{MaxCumulativeGasUsed: DefaultMaxCumulativeGasUsed},
   597  		SequenceSender: &SequenceSenderConfig{
   598  			WaitPeriodSendSequence:                   DefaultWaitPeriodSendSequence,
   599  			LastBatchVirtualizationTimeMaxWaitPeriod: DefaultWaitPeriodSendSequence,
   600  			MaxBatchesForL1:                          MaxBatchesForL1,
   601  			SenderAddress:                            DefaultSequencerAddress,
   602  			PrivateKey:                               DefaultSequencerPrivateKey},
   603  	}
   604  }
   605  
   606  // GetClient returns an ethereum client to the provided URL
   607  func GetClient(URL string) (*ethclient.Client, error) {
   608  	client, err := ethclient.Dial(URL)
   609  	if err != nil {
   610  		return nil, err
   611  	}
   612  	return client, nil
   613  }
   614  
   615  // MustGetClient GetClient but panic if err
   616  func MustGetClient(URL string) *ethclient.Client {
   617  	client, err := GetClient(URL)
   618  	if err != nil {
   619  		panic(err)
   620  	}
   621  	return client
   622  }
   623  
   624  func initOrResetDB() {
   625  	if err := dbutils.InitOrResetState(stateDBCfg); err != nil {
   626  		panic(err)
   627  	}
   628  	if err := dbutils.InitOrResetPool(poolDBCfg); err != nil {
   629  		panic(err)
   630  	}
   631  }