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 }