From 81e3818b237a540714ae22642ada13a391d457fe Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Wed, 14 Sep 2022 09:06:24 +0200 Subject: [PATCH 01/23] tree: introduce lazy init wrapper --- common/prove/witness_helper.go | 12 ++-- core/executor/register_zns_executor.go | 10 ++-- core/statedb/statedb.go | 2 +- service/witness/witness/witness.go | 2 +- tree/account_tree.go | 38 ++++++------ tree/lazy_tree_wrapper.go | 80 ++++++++++++++++++++++++++ tree/util.go | 4 +- 7 files changed, 117 insertions(+), 31 deletions(-) create mode 100644 tree/lazy_tree_wrapper.go diff --git a/common/prove/witness_helper.go b/common/prove/witness_helper.go index 9c66192e8..489893dcc 100644 --- a/common/prove/witness_helper.go +++ b/common/prove/witness_helper.go @@ -38,13 +38,13 @@ type WitnessHelper struct { // Trees accountTree bsmt.SparseMerkleTree - assetTrees *[]bsmt.SparseMerkleTree + assetTrees *[]tree.LazyTreeWrapper liquidityTree bsmt.SparseMerkleTree nftTree bsmt.SparseMerkleTree } func NewWitnessHelper(treeCtx *tree.Context, accountTree, liquidityTree, nftTree bsmt.SparseMerkleTree, - assetTrees *[]bsmt.SparseMerkleTree, accountModel AccountModel) *WitnessHelper { + assetTrees *[]tree.LazyTreeWrapper, accountModel AccountModel) *WitnessHelper { return &WitnessHelper{ treeCtx: treeCtx, accountModel: accountModel, @@ -205,10 +205,10 @@ func (w *WitnessHelper) constructAccountWitness( return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, fmt.Errorf("invalid key") } - emptyAccountAssetTree, err := tree.NewEmptyAccountAssetTree(w.treeCtx, accountKey, finalityBlockNr) - if err != nil { - return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err - } + emptyAccountAssetTree := tree.NewEmptyAccountAssetTree(w.treeCtx, accountKey, finalityBlockNr) + // if err != nil { + // return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err + // } *w.assetTrees = append(*w.assetTrees, emptyAccountAssetTree) cryptoAccount = std.EmptyAccount(accountKey, tree.NilAccountAssetRoot) // update account info diff --git a/core/executor/register_zns_executor.go b/core/executor/register_zns_executor.go index 5718ccfb9..7c2fcf5d0 100644 --- a/core/executor/register_zns_executor.go +++ b/core/executor/register_zns_executor.go @@ -96,11 +96,11 @@ func (e *RegisterZnsExecutor) ApplyTransaction() error { return err } - emptyAssetTree, err := tree.NewEmptyAccountAssetTree(bc.StateDB().TreeCtx, txInfo.AccountIndex, uint64(bc.CurrentBlock().BlockHeight)) - if err != nil { - logx.Errorf("new empty account asset tree failed: %s", err.Error()) - return err - } + emptyAssetTree := tree.NewEmptyAccountAssetTree(bc.StateDB().TreeCtx, txInfo.AccountIndex, uint64(bc.CurrentBlock().BlockHeight)) + // if err != nil { + // logx.Errorf("new empty account asset tree failed: %s", err.Error()) + // return err + // } bc.StateDB().AccountAssetTrees = append(bc.StateDB().AccountAssetTrees, emptyAssetTree) stateCache := e.bc.StateDB() diff --git a/core/statedb/statedb.go b/core/statedb/statedb.go index d42e85516..b15ecd4aa 100644 --- a/core/statedb/statedb.go +++ b/core/statedb/statedb.go @@ -68,7 +68,7 @@ type StateDB struct { AccountTree bsmt.SparseMerkleTree LiquidityTree bsmt.SparseMerkleTree NftTree bsmt.SparseMerkleTree - AccountAssetTrees []bsmt.SparseMerkleTree + AccountAssetTrees []tree.LazyTreeWrapper TreeCtx *tree.Context } diff --git a/service/witness/witness/witness.go b/service/witness/witness/witness.go index 7a5b37fd5..6f9904927 100644 --- a/service/witness/witness/witness.go +++ b/service/witness/witness/witness.go @@ -43,7 +43,7 @@ type Witness struct { // Trees treeCtx *tree.Context accountTree smt.SparseMerkleTree - assetTrees []smt.SparseMerkleTree + assetTrees []tree.LazyTreeWrapper liquidityTree smt.SparseMerkleTree nftTree smt.SparseMerkleTree taskPool *ants.Pool diff --git a/tree/account_tree.go b/tree/account_tree.go index 078abf7b3..a5633a267 100644 --- a/tree/account_tree.go +++ b/tree/account_tree.go @@ -41,7 +41,7 @@ func InitAccountTree( blockHeight int64, ctx *Context, ) ( - accountTree bsmt.SparseMerkleTree, accountAssetTrees []bsmt.SparseMerkleTree, err error, + accountTree bsmt.SparseMerkleTree, accountAssetTrees []LazyTreeWrapper, err error, ) { accountNums, err := accountHistoryModel.GetValidAccountCount(blockHeight) if err != nil { @@ -52,16 +52,19 @@ func InitAccountTree( opts := ctx.Options(blockHeight) // init account state trees - accountAssetTrees = make([]bsmt.SparseMerkleTree, accountNums) + accountAssetTrees = make([]LazyTreeWrapper, accountNums) for index := int64(0); index < accountNums; index++ { // create account assets tree - accountAssetTrees[index], err = bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), - SetNamespace(ctx, accountAssetNamespace(index)), AssetTreeHeight, NilAccountAssetNodeHash, - opts...) - if err != nil { - logx.Errorf("unable to create new tree by assets: %s", err.Error()) - return nil, nil, err - } + accountAssetTrees[index] = NewLazyTreeWrapper(func() bsmt.SparseMerkleTree { + tree, err := bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), + SetNamespace(ctx, accountAssetNamespace(index)), AssetTreeHeight, NilAccountAssetNodeHash, + opts...) + if err != nil { + logx.Errorf("unable to create new tree by assets: %s", err.Error()) + panic(err.Error()) + } + return tree + }) } accountTree, err = bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), SetNamespace(ctx, AccountPrefix), AccountTreeHeight, NilAccountNodeHash, @@ -132,7 +135,7 @@ func reloadAccountTreeFromRDB( blockHeight int64, offset, limit int, accountTree bsmt.SparseMerkleTree, - accountAssetTrees []bsmt.SparseMerkleTree, + accountAssetTrees []LazyTreeWrapper, ) error { _, accountHistories, err := accountHistoryModel.GetValidAccounts(blockHeight, limit, offset) @@ -259,12 +262,15 @@ func NewEmptyAccountAssetTree( ctx *Context, index int64, blockHeight uint64, -) (tree bsmt.SparseMerkleTree, err error) { - return bsmt.NewBASSparseMerkleTree( - bsmt.NewHasher(mimc.NewMiMC()), - SetNamespace(ctx, accountAssetNamespace(index)), - AssetTreeHeight, NilAccountAssetNodeHash, - ctx.Options(int64(blockHeight))...) +) (tree LazyTreeWrapper) { + return NewLazyTreeWrapper(func() bsmt.SparseMerkleTree { + tree, _ := bsmt.NewBASSparseMerkleTree( + bsmt.NewHasher(mimc.NewMiMC()), + SetNamespace(ctx, accountAssetNamespace(index)), + AssetTreeHeight, NilAccountAssetNodeHash, + ctx.Options(int64(blockHeight))...) + return tree + }) } func NewMemAccountAssetTree() (tree bsmt.SparseMerkleTree, err error) { diff --git a/tree/lazy_tree_wrapper.go b/tree/lazy_tree_wrapper.go new file mode 100644 index 000000000..92de3194a --- /dev/null +++ b/tree/lazy_tree_wrapper.go @@ -0,0 +1,80 @@ +package tree + +import ( + "sync" + + bsmt "github.com/bnb-chain/zkbnb-smt" +) + +type LazyTreeWrapper struct { + doOnce sync.Once + tree bsmt.SparseMerkleTree + initFunc func() bsmt.SparseMerkleTree +} + +func NewLazyTreeWrapper(f func() bsmt.SparseMerkleTree) LazyTreeWrapper { + return LazyTreeWrapper{initFunc: f} +} + +func (tw *LazyTreeWrapper) lazyInit() { + tw.doOnce.Do(func() { + tw.tree = tw.initFunc() + }) +} + +// SparseMerkleTree interface functions + +func (tw *LazyTreeWrapper) Size() uint64 { + tw.lazyInit() + return tw.tree.Size() +} + +func (tw *LazyTreeWrapper) Get(key uint64, version *bsmt.Version) ([]byte, error) { + tw.lazyInit() + return tw.tree.Get(key, version) +} + +func (tw *LazyTreeWrapper) Set(key uint64, val []byte) error { + tw.lazyInit() + return tw.tree.Set(key, val) +} + +func (tw *LazyTreeWrapper) IsEmpty() bool { + tw.lazyInit() + return tw.tree.IsEmpty() +} + +func (tw *LazyTreeWrapper) Root() []byte { + tw.lazyInit() + return tw.tree.Root() +} + +func (tw *LazyTreeWrapper) GetProof(key uint64) (bsmt.Proof, error) { + tw.lazyInit() + return tw.tree.GetProof(key) +} + +func (tw *LazyTreeWrapper) VerifyProof(key uint64, proof bsmt.Proof) bool { + tw.lazyInit() + return tw.tree.VerifyProof(key, proof) +} + +func (tw *LazyTreeWrapper) LatestVersion() bsmt.Version { + tw.lazyInit() + return tw.tree.LatestVersion() +} + +func (tw *LazyTreeWrapper) Reset() { + tw.lazyInit() + tw.tree.Reset() +} + +func (tw *LazyTreeWrapper) Commit(recentVersion *bsmt.Version) (bsmt.Version, error) { + tw.lazyInit() + return tw.tree.Commit(recentVersion) +} + +func (tw *LazyTreeWrapper) Rollback(version bsmt.Version) error { + tw.lazyInit() + return tw.tree.Rollback(version) +} diff --git a/tree/util.go b/tree/util.go index e400d7d2b..f30789a95 100644 --- a/tree/util.go +++ b/tree/util.go @@ -118,7 +118,7 @@ func CommitTrees( pool *ants.Pool, version uint64, accountTree bsmt.SparseMerkleTree, - assetTrees *[]bsmt.SparseMerkleTree, + assetTrees *[]LazyTreeWrapper, liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { @@ -208,7 +208,7 @@ func RollBackTrees( pool *ants.Pool, version uint64, accountTree bsmt.SparseMerkleTree, - assetTrees *[]bsmt.SparseMerkleTree, + assetTrees *[]LazyTreeWrapper, liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { From 643bf9f0f5a3fa62fe2a40aa794eab9e240d0c07 Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Fri, 16 Sep 2022 14:00:56 +0200 Subject: [PATCH 02/23] chore: LRU cache with init functions --- common/prove/witness_helper.go | 22 +++---- common/prove/witness_test.go | 2 +- core/blockchain.go | 2 +- core/executor/register_zns_executor.go | 7 +-- core/statedb/statedb.go | 10 ++-- go.mod | 1 + service/witness/witness/witness.go | 8 +-- tree/account_tree.go | 33 +++++------ tree/lazy_tree_cache.go | 35 +++++++++++ tree/lazy_tree_wrapper.go | 80 -------------------------- tree/util.go | 32 ++++++----- 11 files changed, 91 insertions(+), 141 deletions(-) create mode 100644 tree/lazy_tree_cache.go delete mode 100644 tree/lazy_tree_wrapper.go diff --git a/common/prove/witness_helper.go b/common/prove/witness_helper.go index 489893dcc..a69c42a75 100644 --- a/common/prove/witness_helper.go +++ b/common/prove/witness_helper.go @@ -38,13 +38,13 @@ type WitnessHelper struct { // Trees accountTree bsmt.SparseMerkleTree - assetTrees *[]tree.LazyTreeWrapper + assetTrees *tree.LazyTreeCache liquidityTree bsmt.SparseMerkleTree nftTree bsmt.SparseMerkleTree } func NewWitnessHelper(treeCtx *tree.Context, accountTree, liquidityTree, nftTree bsmt.SparseMerkleTree, - assetTrees *[]tree.LazyTreeWrapper, accountModel AccountModel) *WitnessHelper { + assetTrees *tree.LazyTreeCache, accountModel AccountModel) *WitnessHelper { return &WitnessHelper{ treeCtx: treeCtx, accountModel: accountModel, @@ -201,15 +201,11 @@ func (w *WitnessHelper) constructAccountWitness( } // it means this is a registerZNS tx if proverAccounts == nil { - if accountKey != int64(len(*w.assetTrees)) { + if accountKey != w.assetTrees.Size() { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, fmt.Errorf("invalid key") } - emptyAccountAssetTree := tree.NewEmptyAccountAssetTree(w.treeCtx, accountKey, finalityBlockNr) - // if err != nil { - // return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err - // } - *w.assetTrees = append(*w.assetTrees, emptyAccountAssetTree) + w.assetTrees.Add(tree.NewEmptyAccountAssetTreeFunc(w.treeCtx, accountKey, finalityBlockNr)) cryptoAccount = std.EmptyAccount(accountKey, tree.NilAccountAssetRoot) // update account info accountInfo, err := w.accountModel.GetConfirmedAccountByIndex(accountKey) @@ -242,10 +238,10 @@ func (w *WitnessHelper) constructAccountWitness( AccountPk: pk, Nonce: proverAccountInfo.AccountInfo.Nonce, CollectionNonce: proverAccountInfo.AccountInfo.CollectionNonce, - AssetRoot: (*w.assetTrees)[accountKey].Root(), + AssetRoot: w.assetTrees.Get(accountKey).Root(), } for i, accountAsset := range proverAccountInfo.AccountAssets { - assetMerkleProof, err := (*w.assetTrees)[accountKey].GetProof(uint64(accountAsset.AssetId)) + assetMerkleProof, err := w.assetTrees.Get(accountKey).GetProof(uint64(accountAsset.AssetId)) if err != nil { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err } @@ -279,7 +275,7 @@ func (w *WitnessHelper) constructAccountWitness( if err != nil { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err } - err = (*w.assetTrees)[accountKey].Set(uint64(accountAsset.AssetId), nAssetHash) + err = w.assetTrees.Get(accountKey).Set(uint64(accountAsset.AssetId), nAssetHash) if err != nil { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err } @@ -293,7 +289,7 @@ func (w *WitnessHelper) constructAccountWitness( // padding empty account asset for assetCount < NbAccountAssetsPerAccount { cryptoAccount.AssetsInfo[assetCount] = std.EmptyAccountAsset(LastAccountAssetId) - assetMerkleProof, err := (*w.assetTrees)[accountKey].GetProof(LastAccountAssetId) + assetMerkleProof, err := w.assetTrees.Get(accountKey).GetProof(LastAccountAssetId) if err != nil { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err } @@ -322,7 +318,7 @@ func (w *WitnessHelper) constructAccountWitness( proverAccounts[accountCount].AccountInfo.PublicKey, nonce, collectionNonce, - (*w.assetTrees)[accountKey].Root(), + w.assetTrees.Get(accountKey).Root(), ) if err != nil { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err diff --git a/common/prove/witness_test.go b/common/prove/witness_test.go index e00d5cc56..704db2c5e 100644 --- a/common/prove/witness_test.go +++ b/common/prove/witness_test.go @@ -93,7 +93,7 @@ func getWitnessHelper(blockHeight int64) (*WitnessHelper, error) { accountTree, liquidityTree, nftTree, - &accountAssetTrees, + accountAssetTrees, accountModel), nil } diff --git a/core/blockchain.go b/core/blockchain.go index e13f15832..b275b4c41 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -163,7 +163,7 @@ func (bc *BlockChain) CommitNewBlock(blockSize int, createdAt int64) (*block.Blo } currentHeight := bc.currentBlock.BlockHeight - err = tree.CommitTrees(bc.taskPool, uint64(currentHeight), bc.Statedb.AccountTree, &bc.Statedb.AccountAssetTrees, bc.Statedb.LiquidityTree, bc.Statedb.NftTree) + err = tree.CommitTrees(bc.taskPool, uint64(currentHeight), bc.Statedb.AccountTree, bc.Statedb.AccountAssetTrees, bc.Statedb.LiquidityTree, bc.Statedb.NftTree) if err != nil { return nil, err } diff --git a/core/executor/register_zns_executor.go b/core/executor/register_zns_executor.go index 7c2fcf5d0..2e94b88bd 100644 --- a/core/executor/register_zns_executor.go +++ b/core/executor/register_zns_executor.go @@ -96,12 +96,7 @@ func (e *RegisterZnsExecutor) ApplyTransaction() error { return err } - emptyAssetTree := tree.NewEmptyAccountAssetTree(bc.StateDB().TreeCtx, txInfo.AccountIndex, uint64(bc.CurrentBlock().BlockHeight)) - // if err != nil { - // logx.Errorf("new empty account asset tree failed: %s", err.Error()) - // return err - // } - bc.StateDB().AccountAssetTrees = append(bc.StateDB().AccountAssetTrees, emptyAssetTree) + bc.StateDB().AccountAssetTrees.Add(tree.NewEmptyAccountAssetTreeFunc(bc.StateDB().TreeCtx, txInfo.AccountIndex, uint64(bc.CurrentBlock().BlockHeight))) stateCache := e.bc.StateDB() stateCache.SetPendingNewAccount(txInfo.AccountIndex, formatAccount) diff --git a/core/statedb/statedb.go b/core/statedb/statedb.go index b15ecd4aa..fac14ba3d 100644 --- a/core/statedb/statedb.go +++ b/core/statedb/statedb.go @@ -68,7 +68,7 @@ type StateDB struct { AccountTree bsmt.SparseMerkleTree LiquidityTree bsmt.SparseMerkleTree NftTree bsmt.SparseMerkleTree - AccountAssetTrees []tree.LazyTreeWrapper + AccountAssetTrees *tree.LazyTreeCache TreeCtx *tree.Context } @@ -615,19 +615,19 @@ func (s *StateDB) updateAccountTree(accountIndex int64, assets []int64) error { if err != nil { return fmt.Errorf("compute new account asset leaf failed: %v", err) } - err = s.AccountAssetTrees[accountIndex].Set(uint64(assetId), assetLeaf) + err = s.AccountAssetTrees.Get(accountIndex).Set(uint64(assetId), assetLeaf) if err != nil { return fmt.Errorf("update asset tree failed: %v", err) } } - account.AssetRoot = common.Bytes2Hex(s.AccountAssetTrees[accountIndex].Root()) + account.AssetRoot = common.Bytes2Hex(s.AccountAssetTrees.Get(accountIndex).Root()) nAccountLeafHash, err := tree.ComputeAccountLeafHash( account.AccountNameHash, account.PublicKey, account.Nonce, account.CollectionNonce, - s.AccountAssetTrees[accountIndex].Root(), + s.AccountAssetTrees.Get(accountIndex).Root(), ) if err != nil { return fmt.Errorf("unable to compute account leaf: %v", err) @@ -718,7 +718,7 @@ func (s *StateDB) GetPendingNonce(accountIndex int64) (int64, error) { } func (s *StateDB) GetNextAccountIndex() int64 { - return int64(len(s.AccountAssetTrees)) + return s.AccountAssetTrees.Size() } func (s *StateDB) GetNextNftIndex() int64 { diff --git a/go.mod b/go.mod index c94d68130..8771998cb 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/bnb-chain/zkbnb go 1.17 require ( + github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/panjf2000/ants/v2 v2.5.0 github.com/zeromicro/go-zero v1.3.4 gorm.io/gorm v1.23.4 diff --git a/service/witness/witness/witness.go b/service/witness/witness/witness.go index 6f9904927..aa19e4502 100644 --- a/service/witness/witness/witness.go +++ b/service/witness/witness/witness.go @@ -43,7 +43,7 @@ type Witness struct { // Trees treeCtx *tree.Context accountTree smt.SparseMerkleTree - assetTrees []tree.LazyTreeWrapper + assetTrees *tree.LazyTreeCache liquidityTree smt.SparseMerkleTree nftTree smt.SparseMerkleTree taskPool *ants.Pool @@ -132,7 +132,7 @@ func (w *Witness) initState() error { return err } w.taskPool = taskPool - w.helper = utils.NewWitnessHelper(w.treeCtx, w.accountTree, w.liquidityTree, w.nftTree, &w.assetTrees, w.accountModel) + w.helper = utils.NewWitnessHelper(w.treeCtx, w.accountTree, w.liquidityTree, w.nftTree, w.assetTrees, w.accountModel) return nil } @@ -164,7 +164,7 @@ func (w *Witness) GenerateBlockWitness() (err error) { return fmt.Errorf("failed to construct block witness, err: %v", err) } // Step2: commit trees for witness - err = tree.CommitTrees(w.taskPool, uint64(latestVerifiedBlockNr), w.accountTree, &w.assetTrees, w.liquidityTree, w.nftTree) + err = tree.CommitTrees(w.taskPool, uint64(latestVerifiedBlockNr), w.accountTree, w.assetTrees, w.liquidityTree, w.nftTree) if err != nil { return fmt.Errorf("unable to commit trees after txs is executed, error: %v", err) } @@ -172,7 +172,7 @@ func (w *Witness) GenerateBlockWitness() (err error) { err = w.blockWitnessModel.CreateBlockWitness(blockWitness) if err != nil { // rollback trees - rollBackErr := tree.RollBackTrees(w.taskPool, uint64(block.BlockHeight)-1, w.accountTree, &w.assetTrees, w.liquidityTree, w.nftTree) + rollBackErr := tree.RollBackTrees(w.taskPool, uint64(block.BlockHeight)-1, w.accountTree, w.assetTrees, w.liquidityTree, w.nftTree) if rollBackErr != nil { logx.Errorf("unable to rollback trees %v", rollBackErr) } diff --git a/tree/account_tree.go b/tree/account_tree.go index a5633a267..132820231 100644 --- a/tree/account_tree.go +++ b/tree/account_tree.go @@ -41,7 +41,7 @@ func InitAccountTree( blockHeight int64, ctx *Context, ) ( - accountTree bsmt.SparseMerkleTree, accountAssetTrees []LazyTreeWrapper, err error, + accountTree bsmt.SparseMerkleTree, accountAssetTrees *LazyTreeCache, err error, ) { accountNums, err := accountHistoryModel.GetValidAccountCount(blockHeight) if err != nil { @@ -52,10 +52,10 @@ func InitAccountTree( opts := ctx.Options(blockHeight) // init account state trees - accountAssetTrees = make([]LazyTreeWrapper, accountNums) + accountAssetTrees = NewLazyTreeCache(100) for index := int64(0); index < accountNums; index++ { // create account assets tree - accountAssetTrees[index] = NewLazyTreeWrapper(func() bsmt.SparseMerkleTree { + accountAssetTrees.AddToIndex(index, func() bsmt.SparseMerkleTree { tree, err := bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), SetNamespace(ctx, accountAssetNamespace(index)), AssetTreeHeight, NilAccountAssetNodeHash, opts...) @@ -89,8 +89,8 @@ func InitAccountTree( } } - for i := range accountAssetTrees { - _, err := accountAssetTrees[i].Commit(nil) + for i := int64(0); i < accountAssetTrees.Size(); i++ { + _, err := accountAssetTrees.Get(i).Commit(nil) if err != nil { logx.Errorf("unable to set asset to tree: %s", err.Error()) return nil, nil, err @@ -115,10 +115,11 @@ func InitAccountTree( } } - for i := range accountAssetTrees { - if accountAssetTrees[i].LatestVersion() > bsmt.Version(blockHeight) && !accountAssetTrees[i].IsEmpty() { - logx.Infof("asset tree %d version [%d] is higher than block, rollback to %d", i, accountAssetTrees[i].LatestVersion(), blockHeight) - err := accountAssetTrees[i].Rollback(bsmt.Version(blockHeight)) + for i := int64(0); i < accountAssetTrees.Size(); i++ { + account := accountAssetTrees.Get(i) + if account.LatestVersion() > bsmt.Version(blockHeight) && !account.IsEmpty() { + logx.Infof("asset tree %d version [%d] is higher than block, rollback to %d", i, account.LatestVersion(), blockHeight) + err := account.Rollback(bsmt.Version(blockHeight)) if err != nil { logx.Errorf("unable to rollback asset [%d] tree: %s, version: %d", i, err.Error(), blockHeight) return nil, nil, err @@ -135,7 +136,7 @@ func reloadAccountTreeFromRDB( blockHeight int64, offset, limit int, accountTree bsmt.SparseMerkleTree, - accountAssetTrees []LazyTreeWrapper, + accountAssetTrees *LazyTreeCache, ) error { _, accountHistories, err := accountHistoryModel.GetValidAccounts(blockHeight, limit, offset) @@ -200,7 +201,7 @@ func reloadAccountTreeFromRDB( logx.Errorf("unable to convert asset to node: %s", err.Error()) return err } - err = accountAssetTrees[accountIndex].Set(uint64(assetId), hashVal) + err = accountAssetTrees.Get(accountIndex).Set(uint64(assetId), hashVal) if err != nil { logx.Errorf("unable to set asset to tree: %s", err.Error()) return err @@ -211,7 +212,7 @@ func reloadAccountTreeFromRDB( accountInfoMap[accountIndex].PublicKey, accountInfoMap[accountIndex].Nonce, accountInfoMap[accountIndex].CollectionNonce, - accountAssetTrees[accountIndex].Root(), + accountAssetTrees.Get(accountIndex).Root(), ) if err != nil { logx.Errorf("unable to convert account to node: %s", err.Error()) @@ -258,19 +259,19 @@ func AccountToNode( return hashVal, nil } -func NewEmptyAccountAssetTree( +func NewEmptyAccountAssetTreeFunc( ctx *Context, index int64, blockHeight uint64, -) (tree LazyTreeWrapper) { - return NewLazyTreeWrapper(func() bsmt.SparseMerkleTree { +) func() bsmt.SparseMerkleTree { + return func() bsmt.SparseMerkleTree { tree, _ := bsmt.NewBASSparseMerkleTree( bsmt.NewHasher(mimc.NewMiMC()), SetNamespace(ctx, accountAssetNamespace(index)), AssetTreeHeight, NilAccountAssetNodeHash, ctx.Options(int64(blockHeight))...) return tree - }) + } } func NewMemAccountAssetTree() (tree bsmt.SparseMerkleTree, err error) { diff --git a/tree/lazy_tree_cache.go b/tree/lazy_tree_cache.go new file mode 100644 index 000000000..07adf7534 --- /dev/null +++ b/tree/lazy_tree_cache.go @@ -0,0 +1,35 @@ +package tree + +import ( + bsmt "github.com/bnb-chain/zkbnb-smt" + lru "github.com/hashicorp/golang-lru" +) + +type LazyTreeCache struct { + funcMap map[int64]func() bsmt.SparseMerkleTree + treeCache *lru.Cache +} + +func NewLazyTreeCache(maxSize int) *LazyTreeCache { + l, _ := lru.New(maxSize) + m := make(map[int64]func() bsmt.SparseMerkleTree) + return &LazyTreeCache{funcMap: m, treeCache: l} +} + +func (c *LazyTreeCache) AddToIndex(i int64, f func() bsmt.SparseMerkleTree) { + c.funcMap[i] = f +} + +func (c *LazyTreeCache) Add(f func() bsmt.SparseMerkleTree) { + c.funcMap[int64(len(c.funcMap))] = f +} + +func (c *LazyTreeCache) Get(i int64) bsmt.SparseMerkleTree { + c.treeCache.ContainsOrAdd(i, c.funcMap[i]()) + tree, _ := c.treeCache.Get(i) + return tree.(bsmt.SparseMerkleTree) +} + +func (c *LazyTreeCache) Size() int64 { + return int64(len(c.funcMap)) +} diff --git a/tree/lazy_tree_wrapper.go b/tree/lazy_tree_wrapper.go deleted file mode 100644 index 92de3194a..000000000 --- a/tree/lazy_tree_wrapper.go +++ /dev/null @@ -1,80 +0,0 @@ -package tree - -import ( - "sync" - - bsmt "github.com/bnb-chain/zkbnb-smt" -) - -type LazyTreeWrapper struct { - doOnce sync.Once - tree bsmt.SparseMerkleTree - initFunc func() bsmt.SparseMerkleTree -} - -func NewLazyTreeWrapper(f func() bsmt.SparseMerkleTree) LazyTreeWrapper { - return LazyTreeWrapper{initFunc: f} -} - -func (tw *LazyTreeWrapper) lazyInit() { - tw.doOnce.Do(func() { - tw.tree = tw.initFunc() - }) -} - -// SparseMerkleTree interface functions - -func (tw *LazyTreeWrapper) Size() uint64 { - tw.lazyInit() - return tw.tree.Size() -} - -func (tw *LazyTreeWrapper) Get(key uint64, version *bsmt.Version) ([]byte, error) { - tw.lazyInit() - return tw.tree.Get(key, version) -} - -func (tw *LazyTreeWrapper) Set(key uint64, val []byte) error { - tw.lazyInit() - return tw.tree.Set(key, val) -} - -func (tw *LazyTreeWrapper) IsEmpty() bool { - tw.lazyInit() - return tw.tree.IsEmpty() -} - -func (tw *LazyTreeWrapper) Root() []byte { - tw.lazyInit() - return tw.tree.Root() -} - -func (tw *LazyTreeWrapper) GetProof(key uint64) (bsmt.Proof, error) { - tw.lazyInit() - return tw.tree.GetProof(key) -} - -func (tw *LazyTreeWrapper) VerifyProof(key uint64, proof bsmt.Proof) bool { - tw.lazyInit() - return tw.tree.VerifyProof(key, proof) -} - -func (tw *LazyTreeWrapper) LatestVersion() bsmt.Version { - tw.lazyInit() - return tw.tree.LatestVersion() -} - -func (tw *LazyTreeWrapper) Reset() { - tw.lazyInit() - tw.tree.Reset() -} - -func (tw *LazyTreeWrapper) Commit(recentVersion *bsmt.Version) (bsmt.Version, error) { - tw.lazyInit() - return tw.tree.Commit(recentVersion) -} - -func (tw *LazyTreeWrapper) Rollback(version bsmt.Version) error { - tw.lazyInit() - return tw.tree.Rollback(version) -} diff --git a/tree/util.go b/tree/util.go index f30789a95..c7faab07c 100644 --- a/tree/util.go +++ b/tree/util.go @@ -118,11 +118,11 @@ func CommitTrees( pool *ants.Pool, version uint64, accountTree bsmt.SparseMerkleTree, - assetTrees *[]LazyTreeWrapper, + assetTrees *LazyTreeCache, liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { - totalTask := len(*assetTrees) + 3 + totalTask := assetTrees.Size() + 3 errChan := make(chan error, totalTask) defer close(errChan) @@ -142,14 +142,15 @@ func CommitTrees( return err } - for idx := range *assetTrees { - err := func(i int) error { + for idx := int64(0); idx < assetTrees.Size(); idx++ { + err := func(i int64) error { return pool.Submit(func() { assetPrunedVersion := bsmt.Version(version) - if (*assetTrees)[i].LatestVersion() < assetPrunedVersion { - assetPrunedVersion = (*assetTrees)[i].LatestVersion() + asset := assetTrees.Get(i) + if asset.LatestVersion() < assetPrunedVersion { + assetPrunedVersion = asset.LatestVersion() } - ver, err := (*assetTrees)[i].Commit(&assetPrunedVersion) + ver, err := asset.Commit(&assetPrunedVersion) if err != nil { errChan <- errors.Wrapf(err, "unable to commit asset tree [%d], tree ver: %d, prune ver: %d", i, ver, assetPrunedVersion) return @@ -194,7 +195,7 @@ func CommitTrees( return err } - for i := 0; i < totalTask; i++ { + for i := int64(0); i < totalTask; i++ { err := <-errChan if err != nil { return err @@ -208,11 +209,11 @@ func RollBackTrees( pool *ants.Pool, version uint64, accountTree bsmt.SparseMerkleTree, - assetTrees *[]LazyTreeWrapper, + assetTrees *LazyTreeCache, liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { - totalTask := len(*assetTrees) + 3 + totalTask := assetTrees.Size() + 3 errChan := make(chan error, totalTask) defer close(errChan) @@ -231,11 +232,12 @@ func RollBackTrees( return err } - for idx := range *assetTrees { - err := func(i int) error { + for idx := int64(0); idx < assetTrees.Size(); idx++ { + err := func(i int64) error { return pool.Submit(func() { - if (*assetTrees)[i].LatestVersion() > ver && !(*assetTrees)[i].IsEmpty() { - err := (*assetTrees)[i].Rollback(ver) + asset := assetTrees.Get(i) + if asset.LatestVersion() > ver && !asset.IsEmpty() { + err := asset.Rollback(ver) if err != nil { errChan <- errors.Wrapf(err, "unable to rollback asset tree [%d], ver: %d", i, ver) return @@ -277,7 +279,7 @@ func RollBackTrees( return err } - for i := 0; i < totalTask; i++ { + for i := int64(0); i < totalTask; i++ { err := <-errChan if err != nil { return err From 5e905c24dca2b2dd49497e48e070f5d06f4376f1 Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Tue, 20 Sep 2022 10:33:28 +0200 Subject: [PATCH 03/23] tree: improve commit and rollback for asset trees --- common/prove/witness_helper.go | 4 +- core/statedb/statedb.go | 2 +- go.mod | 2 +- go.sum | 2 + service/witness/witness/witness.go | 2 +- tree/account_tree.go | 4 +- tree/lazy_tree_cache.go | 66 ++++++++++++++++++++++++------ tree/util.go | 30 +++++++------- 8 files changed, 77 insertions(+), 35 deletions(-) diff --git a/common/prove/witness_helper.go b/common/prove/witness_helper.go index a69c42a75..fba2224b5 100644 --- a/common/prove/witness_helper.go +++ b/common/prove/witness_helper.go @@ -38,13 +38,13 @@ type WitnessHelper struct { // Trees accountTree bsmt.SparseMerkleTree - assetTrees *tree.LazyTreeCache + assetTrees *tree.AssetTreeCache liquidityTree bsmt.SparseMerkleTree nftTree bsmt.SparseMerkleTree } func NewWitnessHelper(treeCtx *tree.Context, accountTree, liquidityTree, nftTree bsmt.SparseMerkleTree, - assetTrees *tree.LazyTreeCache, accountModel AccountModel) *WitnessHelper { + assetTrees *tree.AssetTreeCache, accountModel AccountModel) *WitnessHelper { return &WitnessHelper{ treeCtx: treeCtx, accountModel: accountModel, diff --git a/core/statedb/statedb.go b/core/statedb/statedb.go index fac14ba3d..081e39da9 100644 --- a/core/statedb/statedb.go +++ b/core/statedb/statedb.go @@ -68,7 +68,7 @@ type StateDB struct { AccountTree bsmt.SparseMerkleTree LiquidityTree bsmt.SparseMerkleTree NftTree bsmt.SparseMerkleTree - AccountAssetTrees *tree.LazyTreeCache + AccountAssetTrees *tree.AssetTreeCache TreeCtx *tree.Context } diff --git a/go.mod b/go.mod index 8771998cb..e6c5e055f 100644 --- a/go.mod +++ b/go.mod @@ -89,7 +89,7 @@ require ( require ( github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220909070525-d913bbbcbe90 github.com/bnb-chain/zkbnb-eth-rpc v0.0.2-0.20220913131900-b3723fd9a82d - github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220907130044-9c7cccbd19fa + github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f github.com/consensys/gnark v0.7.0 github.com/consensys/gnark-crypto v0.7.0 github.com/eko/gocache/v2 v2.3.1 diff --git a/go.sum b/go.sum index 0b022b5a4..ef1992b82 100644 --- a/go.sum +++ b/go.sum @@ -123,6 +123,8 @@ github.com/bnb-chain/zkbnb-eth-rpc v0.0.2-0.20220913131900-b3723fd9a82d h1:tE3GJ github.com/bnb-chain/zkbnb-eth-rpc v0.0.2-0.20220913131900-b3723fd9a82d/go.mod h1:w3x3DxF1Iz1ebep21cdmb73mOyyU1Phd8s10SAgRNHg= github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220907130044-9c7cccbd19fa h1:aVqkz6Ge3eW7SKmINYMprpxq2VNpKp4vKQ6dEue8uUE= github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220907130044-9c7cccbd19fa/go.mod h1:mGIAve72dt/VOVQ2wu7UjcjnMspnKczi5QACE1NGVec= +github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f h1:zBVWOWlH4w18O6wp0gZML4U2n1rxsFLb7KB7DFE8zcQ= +github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f/go.mod h1:mGIAve72dt/VOVQ2wu7UjcjnMspnKczi5QACE1NGVec= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d h1:pVrfxiGfwelyab6n21ZBkbkmbevaf+WvMIiR7sr97hw= github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= diff --git a/service/witness/witness/witness.go b/service/witness/witness/witness.go index aa19e4502..33a43d203 100644 --- a/service/witness/witness/witness.go +++ b/service/witness/witness/witness.go @@ -43,7 +43,7 @@ type Witness struct { // Trees treeCtx *tree.Context accountTree smt.SparseMerkleTree - assetTrees *tree.LazyTreeCache + assetTrees *tree.AssetTreeCache liquidityTree smt.SparseMerkleTree nftTree smt.SparseMerkleTree taskPool *ants.Pool diff --git a/tree/account_tree.go b/tree/account_tree.go index 132820231..a7a3b07f1 100644 --- a/tree/account_tree.go +++ b/tree/account_tree.go @@ -41,7 +41,7 @@ func InitAccountTree( blockHeight int64, ctx *Context, ) ( - accountTree bsmt.SparseMerkleTree, accountAssetTrees *LazyTreeCache, err error, + accountTree bsmt.SparseMerkleTree, accountAssetTrees *AssetTreeCache, err error, ) { accountNums, err := accountHistoryModel.GetValidAccountCount(blockHeight) if err != nil { @@ -136,7 +136,7 @@ func reloadAccountTreeFromRDB( blockHeight int64, offset, limit int, accountTree bsmt.SparseMerkleTree, - accountAssetTrees *LazyTreeCache, + accountAssetTrees *AssetTreeCache, ) error { _, accountHistories, err := accountHistoryModel.GetValidAccounts(blockHeight, limit, offset) diff --git a/tree/lazy_tree_cache.go b/tree/lazy_tree_cache.go index 07adf7534..778bf4b2a 100644 --- a/tree/lazy_tree_cache.go +++ b/tree/lazy_tree_cache.go @@ -1,35 +1,75 @@ package tree import ( + "sync" + bsmt "github.com/bnb-chain/zkbnb-smt" lru "github.com/hashicorp/golang-lru" ) -type LazyTreeCache struct { - funcMap map[int64]func() bsmt.SparseMerkleTree - treeCache *lru.Cache +type AssetTreeCache struct { + funcMap map[int64]func() bsmt.SparseMerkleTree + funcLock sync.RWMutex + commitMap map[int64]bool + CommitLock sync.RWMutex + treeCache *lru.Cache } -func NewLazyTreeCache(maxSize int) *LazyTreeCache { - l, _ := lru.New(maxSize) - m := make(map[int64]func() bsmt.SparseMerkleTree) - return &LazyTreeCache{funcMap: m, treeCache: l} +func NewLazyTreeCache(maxSize int) *AssetTreeCache { + cache := AssetTreeCache{funcMap: make(map[int64]func() bsmt.SparseMerkleTree), commitMap: make(map[int64]bool)} + cache.treeCache, _ = lru.NewWithEvict(maxSize, cache.OnDelete) + return &cache } -func (c *LazyTreeCache) AddToIndex(i int64, f func() bsmt.SparseMerkleTree) { +func (c *AssetTreeCache) AddToIndex(i int64, f func() bsmt.SparseMerkleTree) { + c.funcLock.Lock() c.funcMap[i] = f + c.funcLock.Unlock() } -func (c *LazyTreeCache) Add(f func() bsmt.SparseMerkleTree) { +func (c *AssetTreeCache) Add(f func() bsmt.SparseMerkleTree) { + c.funcLock.Lock() c.funcMap[int64(len(c.funcMap))] = f + c.funcLock.Unlock() } -func (c *LazyTreeCache) Get(i int64) bsmt.SparseMerkleTree { +func (c *AssetTreeCache) Get(i int64) (tree bsmt.SparseMerkleTree) { + c.funcLock.RLock() c.treeCache.ContainsOrAdd(i, c.funcMap[i]()) - tree, _ := c.treeCache.Get(i) - return tree.(bsmt.SparseMerkleTree) + c.funcLock.RUnlock() + if tmpTree, ok := c.treeCache.Get(i); ok { + tree = tmpTree.(bsmt.SparseMerkleTree) + } + c.CommitLock.Lock() + c.commitMap[i] = (tree.LatestVersion()-tree.RecentVersion() > 1) + c.CommitLock.Unlock() + return +} + +func (c *AssetTreeCache) NeedsCommit(i int64) (ret bool) { + if c.treeCache.Contains(i) { + if tree, ok := c.treeCache.Peek(i); ok { + c.CommitLock.Lock() + c.commitMap[i] = (tree.(bsmt.SparseMerkleTree).LatestVersion()-tree.(bsmt.SparseMerkleTree).RecentVersion() > 1) + ret = c.commitMap[i] + c.CommitLock.Unlock() + return + } + } + c.CommitLock.RLock() + ret = c.commitMap[i] + c.CommitLock.RUnlock() + return +} + +func (c *AssetTreeCache) OnDelete(k, v interface{}) { + c.CommitLock.Lock() + c.commitMap[k.(int64)] = (v.(bsmt.SparseMerkleTree).LatestVersion()-v.(bsmt.SparseMerkleTree).RecentVersion() > 1) + c.CommitLock.Unlock() } -func (c *LazyTreeCache) Size() int64 { +func (c *AssetTreeCache) Size() int64 { + c.funcLock.RLock() + defer c.funcLock.RUnlock() return int64(len(c.funcMap)) } diff --git a/tree/util.go b/tree/util.go index c7faab07c..c04f1e02c 100644 --- a/tree/util.go +++ b/tree/util.go @@ -118,7 +118,7 @@ func CommitTrees( pool *ants.Pool, version uint64, accountTree bsmt.SparseMerkleTree, - assetTrees *LazyTreeCache, + assetTrees *AssetTreeCache, liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { @@ -145,15 +145,14 @@ func CommitTrees( for idx := int64(0); idx < assetTrees.Size(); idx++ { err := func(i int64) error { return pool.Submit(func() { - assetPrunedVersion := bsmt.Version(version) - asset := assetTrees.Get(i) - if asset.LatestVersion() < assetPrunedVersion { - assetPrunedVersion = asset.LatestVersion() - } - ver, err := asset.Commit(&assetPrunedVersion) - if err != nil { - errChan <- errors.Wrapf(err, "unable to commit asset tree [%d], tree ver: %d, prune ver: %d", i, ver, assetPrunedVersion) - return + if assetTrees.NeedsCommit(i) { + asset := assetTrees.Get(i) + version := asset.LatestVersion() + ver, err := asset.Commit(&version) + if err != nil { + errChan <- errors.Wrapf(err, "unable to commit asset tree [%d], tree ver: %d, prune ver: %d", i, ver, version) + return + } } errChan <- nil }) @@ -209,7 +208,7 @@ func RollBackTrees( pool *ants.Pool, version uint64, accountTree bsmt.SparseMerkleTree, - assetTrees *LazyTreeCache, + assetTrees *AssetTreeCache, liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { @@ -235,11 +234,12 @@ func RollBackTrees( for idx := int64(0); idx < assetTrees.Size(); idx++ { err := func(i int64) error { return pool.Submit(func() { - asset := assetTrees.Get(i) - if asset.LatestVersion() > ver && !asset.IsEmpty() { - err := asset.Rollback(ver) + if assetTrees.NeedsCommit(i) { + asset := assetTrees.Get(i) + version := asset.RecentVersion() + err := asset.Rollback(version) if err != nil { - errChan <- errors.Wrapf(err, "unable to rollback asset tree [%d], ver: %d", i, ver) + errChan <- errors.Wrapf(err, "unable to rollback asset tree [%d], ver: %d", i, version) return } } From b393c21bf8e47d530912e026418eb5cba829e143 Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Wed, 21 Sep 2022 09:08:03 +0200 Subject: [PATCH 04/23] tree: cache small improvements --- tree/account_tree.go | 2 +- tree/{lazy_tree_cache.go => asset_tree_cache.go} | 16 ++++------------ types/constant.go | 2 ++ 3 files changed, 7 insertions(+), 13 deletions(-) rename tree/{lazy_tree_cache.go => asset_tree_cache.go} (78%) diff --git a/tree/account_tree.go b/tree/account_tree.go index b66af4563..cbae2d6a1 100644 --- a/tree/account_tree.go +++ b/tree/account_tree.go @@ -52,7 +52,7 @@ func InitAccountTree( opts := ctx.Options(blockHeight) // init account state trees - accountAssetTrees = NewLazyTreeCache(100) + accountAssetTrees = NewLazyTreeCache(types.AssetTreeCacheSize) for index := int64(0); index < accountNums; index++ { // create account assets tree accountAssetTrees.AddToIndex(index, func() bsmt.SparseMerkleTree { diff --git a/tree/lazy_tree_cache.go b/tree/asset_tree_cache.go similarity index 78% rename from tree/lazy_tree_cache.go rename to tree/asset_tree_cache.go index 778bf4b2a..428072442 100644 --- a/tree/lazy_tree_cache.go +++ b/tree/asset_tree_cache.go @@ -40,26 +40,18 @@ func (c *AssetTreeCache) Get(i int64) (tree bsmt.SparseMerkleTree) { if tmpTree, ok := c.treeCache.Get(i); ok { tree = tmpTree.(bsmt.SparseMerkleTree) } - c.CommitLock.Lock() - c.commitMap[i] = (tree.LatestVersion()-tree.RecentVersion() > 1) - c.CommitLock.Unlock() return } -func (c *AssetTreeCache) NeedsCommit(i int64) (ret bool) { +func (c *AssetTreeCache) NeedsCommit(i int64) bool { if c.treeCache.Contains(i) { if tree, ok := c.treeCache.Peek(i); ok { - c.CommitLock.Lock() - c.commitMap[i] = (tree.(bsmt.SparseMerkleTree).LatestVersion()-tree.(bsmt.SparseMerkleTree).RecentVersion() > 1) - ret = c.commitMap[i] - c.CommitLock.Unlock() - return + return (tree.(bsmt.SparseMerkleTree).LatestVersion()-tree.(bsmt.SparseMerkleTree).RecentVersion() > 1) } } c.CommitLock.RLock() - ret = c.commitMap[i] - c.CommitLock.RUnlock() - return + defer c.funcLock.RUnlock() + return c.commitMap[i] } func (c *AssetTreeCache) OnDelete(k, v interface{}) { diff --git a/types/constant.go b/types/constant.go index 92ef0863c..c3dd2a16b 100644 --- a/types/constant.go +++ b/types/constant.go @@ -48,6 +48,8 @@ const ( BNBAssetId = 0 BNBDecimals = "1000000000000000000" + + AssetTreeCacheSize = 256 ) var ( From 0512614448d205e27c0b1b8b11e388db5ba0198f Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Wed, 21 Sep 2022 16:57:31 +0200 Subject: [PATCH 05/23] tree: performance improvements for asset tree cache based on review --- common/prove/witness_helper.go | 4 +- core/executor/register_zns_executor.go | 2 +- core/statedb/statedb.go | 2 +- tree/account_tree.go | 47 +++++++------ tree/asset_tree_cache.go | 91 ++++++++++++++++---------- tree/util.go | 42 ++++++------ 6 files changed, 102 insertions(+), 86 deletions(-) diff --git a/common/prove/witness_helper.go b/common/prove/witness_helper.go index 48f3f1de1..8d3b3b794 100644 --- a/common/prove/witness_helper.go +++ b/common/prove/witness_helper.go @@ -203,11 +203,11 @@ func (w *WitnessHelper) constructAccountWitness( } // it means this is a registerZNS tx if proverAccounts == nil { - if accountKey != w.assetTrees.Size() { + if accountKey != w.assetTrees.GetNextAccountIndex() { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, fmt.Errorf("invalid key") } - w.assetTrees.Add(tree.NewEmptyAccountAssetTreeFunc(w.treeCtx, accountKey, finalityBlockNr)) + w.assetTrees.UpdateCache(accountKey, tree.NewEmptyAccountAssetTreeFunc(w.treeCtx, finalityBlockNr)) cryptoAccount = cryptoTypes.EmptyAccount(accountKey, tree.NilAccountAssetRoot) // update account info accountInfo, err := w.accountModel.GetConfirmedAccountByIndex(accountKey) diff --git a/core/executor/register_zns_executor.go b/core/executor/register_zns_executor.go index d0f2b68d4..b90ee4bd5 100644 --- a/core/executor/register_zns_executor.go +++ b/core/executor/register_zns_executor.go @@ -96,7 +96,7 @@ func (e *RegisterZnsExecutor) ApplyTransaction() error { return err } - bc.StateDB().AccountAssetTrees.Add(tree.NewEmptyAccountAssetTreeFunc(bc.StateDB().TreeCtx, txInfo.AccountIndex, uint64(bc.CurrentBlock().BlockHeight))) + bc.StateDB().AccountAssetTrees.UpdateCache(txInfo.AccountIndex, tree.NewEmptyAccountAssetTreeFunc(bc.StateDB().TreeCtx, uint64(bc.CurrentBlock().BlockHeight))) stateCache := e.bc.StateDB() stateCache.SetPendingNewAccount(txInfo.AccountIndex, formatAccount) diff --git a/core/statedb/statedb.go b/core/statedb/statedb.go index c608ddac8..c4c674ce8 100644 --- a/core/statedb/statedb.go +++ b/core/statedb/statedb.go @@ -717,7 +717,7 @@ func (s *StateDB) GetPendingNonce(accountIndex int64) (int64, error) { } func (s *StateDB) GetNextAccountIndex() int64 { - return s.AccountAssetTrees.Size() + return s.AccountAssetTrees.GetNextAccountIndex() } func (s *StateDB) GetNextNftIndex() int64 { diff --git a/tree/account_tree.go b/tree/account_tree.go index cbae2d6a1..d9d4e07ff 100644 --- a/tree/account_tree.go +++ b/tree/account_tree.go @@ -52,20 +52,16 @@ func InitAccountTree( opts := ctx.Options(blockHeight) // init account state trees - accountAssetTrees = NewLazyTreeCache(types.AssetTreeCacheSize) - for index := int64(0); index < accountNums; index++ { - // create account assets tree - accountAssetTrees.AddToIndex(index, func() bsmt.SparseMerkleTree { - tree, err := bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), - SetNamespace(ctx, accountAssetNamespace(index)), AssetTreeHeight, NilAccountAssetNodeHash, - opts...) - if err != nil { - logx.Errorf("unable to create new tree by assets: %s", err.Error()) - panic(err.Error()) - } - return tree - }) - } + accountAssetTrees = NewLazyTreeCache(types.AssetTreeCacheSize, accountNums-1, func(index int64) bsmt.SparseMerkleTree { + tree, err := bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), + SetNamespace(ctx, accountAssetNamespace(index)), AssetTreeHeight, NilAccountAssetNodeHash, + opts...) + if err != nil { + logx.Errorf("unable to create new tree by assets: %s", err.Error()) + panic(err.Error()) + } + return tree + }) accountTree, err = bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), SetNamespace(ctx, AccountPrefix), AccountTreeHeight, NilAccountNodeHash, opts...) @@ -89,7 +85,7 @@ func InitAccountTree( } } - for i := int64(0); i < accountAssetTrees.Size(); i++ { + for i := int64(0); i < accountNums; i++ { _, err := accountAssetTrees.Get(i).Commit(nil) if err != nil { logx.Errorf("unable to set asset to tree: %s", err.Error()) @@ -115,11 +111,11 @@ func InitAccountTree( } } - for i := int64(0); i < accountAssetTrees.Size(); i++ { - account := accountAssetTrees.Get(i) - if account.LatestVersion() > bsmt.Version(blockHeight) && !account.IsEmpty() { - logx.Infof("asset tree %d version [%d] is higher than block, rollback to %d", i, account.LatestVersion(), blockHeight) - err := account.Rollback(bsmt.Version(blockHeight)) + for i := int64(0); i < accountNums; i++ { + asset := accountAssetTrees.Get(i) + if asset.LatestVersion() > bsmt.Version(blockHeight) && !asset.IsEmpty() { + logx.Infof("asset tree %d version [%d] is higher than block, rollback to %d", i, asset.LatestVersion(), blockHeight) + err := asset.Rollback(bsmt.Version(blockHeight)) if err != nil { logx.Errorf("unable to rollback asset [%d] tree: %s, version: %d", i, err.Error(), blockHeight) return nil, nil, err @@ -261,15 +257,18 @@ func AccountToNode( func NewEmptyAccountAssetTreeFunc( ctx *Context, - index int64, blockHeight uint64, -) func() bsmt.SparseMerkleTree { - return func() bsmt.SparseMerkleTree { - tree, _ := bsmt.NewBASSparseMerkleTree( +) func(index int64) bsmt.SparseMerkleTree { + return func(index int64) bsmt.SparseMerkleTree { + tree, err := bsmt.NewBASSparseMerkleTree( bsmt.NewHasher(mimc.NewMiMC()), SetNamespace(ctx, accountAssetNamespace(index)), AssetTreeHeight, NilAccountAssetNodeHash, ctx.Options(int64(blockHeight))...) + if err != nil { + logx.Errorf("unable to create new tree by assets: %s", err.Error()) + panic(err.Error()) + } return tree } } diff --git a/tree/asset_tree_cache.go b/tree/asset_tree_cache.go index 428072442..e9cb591b2 100644 --- a/tree/asset_tree_cache.go +++ b/tree/asset_tree_cache.go @@ -7,61 +7,80 @@ import ( lru "github.com/hashicorp/golang-lru" ) +// Lazy init cache for asset trees type AssetTreeCache struct { - funcMap map[int64]func() bsmt.SparseMerkleTree - funcLock sync.RWMutex - commitMap map[int64]bool - CommitLock sync.RWMutex - treeCache *lru.Cache + initFunction func(index int64) bsmt.SparseMerkleTree + nextAccountNumber int64 + mainLock sync.RWMutex + changes map[int64]bool + changesLock sync.RWMutex + treeCache *lru.Cache } -func NewLazyTreeCache(maxSize int) *AssetTreeCache { - cache := AssetTreeCache{funcMap: make(map[int64]func() bsmt.SparseMerkleTree), commitMap: make(map[int64]bool)} - cache.treeCache, _ = lru.NewWithEvict(maxSize, cache.OnDelete) +// Creates new AssetTreeCache +// maxSize defines the maximum size of currently initialized trees +// accountNumber defines the number of accounts to create/or next index for new account +func NewLazyTreeCache(maxSize int, accountNumber int64, f func(index int64) bsmt.SparseMerkleTree) *AssetTreeCache { + cache := AssetTreeCache{initFunction: f, nextAccountNumber: accountNumber, changes: make(map[int64]bool, maxSize*10)} + cache.treeCache, _ = lru.NewWithEvict(maxSize, cache.onDelete) return &cache } -func (c *AssetTreeCache) AddToIndex(i int64, f func() bsmt.SparseMerkleTree) { - c.funcLock.Lock() - c.funcMap[i] = f - c.funcLock.Unlock() +// Updates current cache with new(updated) init function and with latest account index +func (c *AssetTreeCache) UpdateCache(accountNumber int64, f func(index int64) bsmt.SparseMerkleTree) { + c.mainLock.Lock() + c.initFunction = f + if c.nextAccountNumber < accountNumber { + c.nextAccountNumber = accountNumber + } + c.mainLock.Unlock() } -func (c *AssetTreeCache) Add(f func() bsmt.SparseMerkleTree) { - c.funcLock.Lock() - c.funcMap[int64(len(c.funcMap))] = f - c.funcLock.Unlock() +// Returns index of next account +func (c *AssetTreeCache) GetNextAccountIndex() int64 { + c.mainLock.RLock() + defer c.mainLock.RUnlock() + return c.nextAccountNumber + 1 } +// Returns asset tree based on account index func (c *AssetTreeCache) Get(i int64) (tree bsmt.SparseMerkleTree) { - c.funcLock.RLock() - c.treeCache.ContainsOrAdd(i, c.funcMap[i]()) - c.funcLock.RUnlock() + c.mainLock.RLock() + c.treeCache.ContainsOrAdd(i, c.initFunction(i)) + c.mainLock.RUnlock() if tmpTree, ok := c.treeCache.Get(i); ok { tree = tmpTree.(bsmt.SparseMerkleTree) } return } -func (c *AssetTreeCache) NeedsCommit(i int64) bool { - if c.treeCache.Contains(i) { - if tree, ok := c.treeCache.Peek(i); ok { - return (tree.(bsmt.SparseMerkleTree).LatestVersion()-tree.(bsmt.SparseMerkleTree).RecentVersion() > 1) +// Returns slice of indexes of asset trees that were changned +// and resets cache of the marked changes of asset trees. +func (c *AssetTreeCache) GetChanges() []int64 { + c.mainLock.Lock() + c.changesLock.Lock() + defer c.mainLock.Unlock() + defer c.changesLock.Unlock() + for _, key := range c.treeCache.Keys() { + tree, _ := c.treeCache.Peek(key) + if tree.(bsmt.SparseMerkleTree).LatestVersion()-tree.(bsmt.SparseMerkleTree).RecentVersion() > 1 { + c.changes[key.(int64)] = true } } - c.CommitLock.RLock() - defer c.funcLock.RUnlock() - return c.commitMap[i] -} - -func (c *AssetTreeCache) OnDelete(k, v interface{}) { - c.CommitLock.Lock() - c.commitMap[k.(int64)] = (v.(bsmt.SparseMerkleTree).LatestVersion()-v.(bsmt.SparseMerkleTree).RecentVersion() > 1) - c.CommitLock.Unlock() + ret := make([]int64, 0, len(c.changes)) + for key := range c.changes { + ret = append(ret, key) + } + // Cleans map + c.changes = make(map[int64]bool, len(c.changes)) + return ret } -func (c *AssetTreeCache) Size() int64 { - c.funcLock.RLock() - defer c.funcLock.RUnlock() - return int64(len(c.funcMap)) +// Internal method to that marks if changes happend to tree eviced from LRU +func (c *AssetTreeCache) onDelete(k, v interface{}) { + c.changesLock.Lock() + if v.(bsmt.SparseMerkleTree).LatestVersion()-v.(bsmt.SparseMerkleTree).RecentVersion() > 1 { + c.changes[k.(int64)] = true + } + c.changesLock.Unlock() } diff --git a/tree/util.go b/tree/util.go index c04f1e02c..2d6fc0a3b 100644 --- a/tree/util.go +++ b/tree/util.go @@ -122,7 +122,8 @@ func CommitTrees( liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { - totalTask := assetTrees.Size() + 3 + assetTreeChanges := assetTrees.GetChanges() + totalTask := len(assetTreeChanges) + 3 errChan := make(chan error, totalTask) defer close(errChan) @@ -142,17 +143,15 @@ func CommitTrees( return err } - for idx := int64(0); idx < assetTrees.Size(); idx++ { + for _, idx := range assetTreeChanges { err := func(i int64) error { return pool.Submit(func() { - if assetTrees.NeedsCommit(i) { - asset := assetTrees.Get(i) - version := asset.LatestVersion() - ver, err := asset.Commit(&version) - if err != nil { - errChan <- errors.Wrapf(err, "unable to commit asset tree [%d], tree ver: %d, prune ver: %d", i, ver, version) - return - } + asset := assetTrees.Get(i) + version := asset.LatestVersion() + ver, err := asset.Commit(&version) + if err != nil { + errChan <- errors.Wrapf(err, "unable to commit asset tree [%d], tree ver: %d, prune ver: %d", i, ver, version) + return } errChan <- nil }) @@ -194,7 +193,7 @@ func CommitTrees( return err } - for i := int64(0); i < totalTask; i++ { + for i := 0; i < totalTask; i++ { err := <-errChan if err != nil { return err @@ -212,7 +211,8 @@ func RollBackTrees( liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { - totalTask := assetTrees.Size() + 3 + assetTreeChanges := assetTrees.GetChanges() + totalTask := len(assetTreeChanges) + 3 errChan := make(chan error, totalTask) defer close(errChan) @@ -231,17 +231,15 @@ func RollBackTrees( return err } - for idx := int64(0); idx < assetTrees.Size(); idx++ { + for _, idx := range assetTreeChanges { err := func(i int64) error { return pool.Submit(func() { - if assetTrees.NeedsCommit(i) { - asset := assetTrees.Get(i) - version := asset.RecentVersion() - err := asset.Rollback(version) - if err != nil { - errChan <- errors.Wrapf(err, "unable to rollback asset tree [%d], ver: %d", i, version) - return - } + asset := assetTrees.Get(i) + version := asset.RecentVersion() + err := asset.Rollback(version) + if err != nil { + errChan <- errors.Wrapf(err, "unable to rollback asset tree [%d], ver: %d", i, version) + return } errChan <- nil }) @@ -279,7 +277,7 @@ func RollBackTrees( return err } - for i := int64(0); i < totalTask; i++ { + for i := 0; i < totalTask; i++ { err := <-errChan if err != nil { return err From 390f9f6c118630ed54b13728fe68752f9283d15b Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Fri, 23 Sep 2022 09:34:06 +0200 Subject: [PATCH 06/23] tree: move cache size to config and small improvment --- common/prove/witness_helper.go | 2 +- common/prove/witness_test.go | 3 ++- core/blockchain.go | 5 ++-- core/executor/register_zns_executor.go | 2 +- core/statedb/statedb.go | 3 ++- deploy-local.sh | 5 ++++ deploy-qa.sh | 7 ++++++ deployment/docker-compose/docker-compose.sh | 2 ++ docs/tree/recovery.md | 1 + service/committer/etc/config.yaml.example | 1 + service/monitor/etc/config.yaml.example | 3 ++- service/witness/config/config.go | 3 ++- service/witness/etc/config.yaml.example | 1 + service/witness/witness/witness.go | 1 + tools/recovery/etc/config.yaml.example | 3 ++- tools/recovery/internal/config/config.go | 3 ++- tools/recovery/recovery.go | 1 + tree/account_tree.go | 23 +++--------------- tree/asset_tree_cache.go | 27 +++++++++++++-------- tree/util.go | 2 ++ types/constant.go | 2 -- 21 files changed, 58 insertions(+), 42 deletions(-) diff --git a/common/prove/witness_helper.go b/common/prove/witness_helper.go index 8d3b3b794..5303db48f 100644 --- a/common/prove/witness_helper.go +++ b/common/prove/witness_helper.go @@ -207,7 +207,7 @@ func (w *WitnessHelper) constructAccountWitness( return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, fmt.Errorf("invalid key") } - w.assetTrees.UpdateCache(accountKey, tree.NewEmptyAccountAssetTreeFunc(w.treeCtx, finalityBlockNr)) + w.assetTrees.UpdateCache(accountKey, int64(finalityBlockNr)) cryptoAccount = cryptoTypes.EmptyAccount(accountKey, tree.NilAccountAssetRoot) // update account info accountInfo, err := w.accountModel.GetConfirmedAccountByIndex(accountKey) diff --git a/common/prove/witness_test.go b/common/prove/witness_test.go index 954f6f048..b52d2c88c 100644 --- a/common/prove/witness_test.go +++ b/common/prove/witness_test.go @@ -46,6 +46,7 @@ var ( accountHistoryModel account.AccountHistoryModel liquidityHistoryModel liquidity.LiquidityHistoryModel nftHistoryModel nft.L2NftHistoryModel + assetTreeCacheSize = 512000 ) func TestConstructTxWitness(t *testing.T) { @@ -77,7 +78,7 @@ func getWitnessHelper(blockHeight int64) (*WitnessHelper, error) { Driver: tree.MemoryDB, TreeDB: memory.NewMemoryDB(), } - accountTree, accountAssetTrees, err := tree.InitAccountTree(accountModel, accountHistoryModel, blockHeight, ctx) + accountTree, accountAssetTrees, err := tree.InitAccountTree(accountModel, accountHistoryModel, blockHeight, ctx, assetTreeCacheSize) if err != nil { return nil, err } diff --git a/core/blockchain.go b/core/blockchain.go index b275b4c41..c31c3556a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -44,7 +44,8 @@ type ChainConfig struct { //nolint:staticcheck LevelDBOption tree.LevelDBOption `json:",optional"` //nolint:staticcheck - RedisDBOption tree.RedisDBOption `json:",optional"` + RedisDBOption tree.RedisDBOption `json:",optional"` + AssetTreeCacheSize int } } @@ -92,7 +93,7 @@ func NewBlockChain(config *ChainConfig, moduleName string) (*BlockChain, error) RedisDBOption: &config.TreeDB.RedisDBOption, } - bc.Statedb, err = sdb.NewStateDB(treeCtx, bc.ChainDB, redisCache, &config.CacheConfig, bc.currentBlock.StateRoot, curHeight) + bc.Statedb, err = sdb.NewStateDB(treeCtx, bc.ChainDB, redisCache, &config.CacheConfig, config.TreeDB.AssetTreeCacheSize, bc.currentBlock.StateRoot, curHeight) if err != nil { return nil, err } diff --git a/core/executor/register_zns_executor.go b/core/executor/register_zns_executor.go index b90ee4bd5..2162b8896 100644 --- a/core/executor/register_zns_executor.go +++ b/core/executor/register_zns_executor.go @@ -96,7 +96,7 @@ func (e *RegisterZnsExecutor) ApplyTransaction() error { return err } - bc.StateDB().AccountAssetTrees.UpdateCache(txInfo.AccountIndex, tree.NewEmptyAccountAssetTreeFunc(bc.StateDB().TreeCtx, uint64(bc.CurrentBlock().BlockHeight))) + bc.StateDB().AccountAssetTrees.UpdateCache(txInfo.AccountIndex, bc.CurrentBlock().BlockHeight) stateCache := e.bc.StateDB() stateCache.SetPendingNewAccount(txInfo.AccountIndex, formatAccount) diff --git a/core/statedb/statedb.go b/core/statedb/statedb.go index c4c674ce8..4fda60c84 100644 --- a/core/statedb/statedb.go +++ b/core/statedb/statedb.go @@ -72,7 +72,7 @@ type StateDB struct { } func NewStateDB(treeCtx *tree.Context, chainDb *ChainDB, - redisCache dbcache.Cache, cacheConfig *CacheConfig, + redisCache dbcache.Cache, cacheConfig *CacheConfig, assetCacheSize int, stateRoot string, curHeight int64) (*StateDB, error) { err := tree.SetupTreeDB(treeCtx) if err != nil { @@ -84,6 +84,7 @@ func NewStateDB(treeCtx *tree.Context, chainDb *ChainDB, chainDb.AccountHistoryModel, curHeight, treeCtx, + assetCacheSize, ) if err != nil { logx.Error("dbinitializer account tree failed:", err) diff --git a/deploy-local.sh b/deploy-local.sh index 6573cd0f5..22a467e13 100644 --- a/deploy-local.sh +++ b/deploy-local.sh @@ -115,6 +115,7 @@ BlockConfig: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ${DEPLOY_PATH}/zkbnb/service/prover/etc/config.yaml echo -e " @@ -140,6 +141,7 @@ CacheRedis: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ${DEPLOY_PATH}/zkbnb/service/witness/etc/config.yaml echo -e " @@ -170,6 +172,7 @@ ChainConfig: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ${DEPLOY_PATH}/zkbnb/service/monitor/etc/config.yaml echo -e " @@ -195,6 +198,7 @@ BlockConfig: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ${DEPLOY_PATH}/zkbnb/service/committer/etc/config.yaml echo -e " @@ -226,6 +230,7 @@ ChainConfig: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ${DEPLOY_PATH}/zkbnb/service/sender/etc/config.yaml echo -e " diff --git a/deploy-qa.sh b/deploy-qa.sh index 1ee50f448..8135b285d 100644 --- a/deploy-qa.sh +++ b/deploy-qa.sh @@ -107,6 +107,7 @@ KeyPath: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ~/zkbnb-deploy/zkbnb/service/cronjob/prover/etc/prover.yaml cd ~/zkbnb-deploy/zkbnb/service/cronjob/prover/ @@ -129,6 +130,7 @@ CacheRedis: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ~/zkbnb-deploy/zkbnb/service/cronjob/witnessGenerator/etc/witnessGenerator.yaml cd ~/zkbnb-deploy/zkbnb/service/cronjob/witnessGenerator/ @@ -162,6 +164,7 @@ ChainConfig: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ~/zkbnb-deploy/zkbnb/service/cronjob/monitor/etc/monitor.yaml cd ~/zkbnb-deploy/zkbnb/service/cronjob/monitor/ @@ -186,6 +189,7 @@ KeyPath: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " >> ~/zkbnb-deploy/zkbnb/service/cronjob/committer/etc/committer.yaml cd ~/zkbnb-deploy/zkbnb/service/cronjob/committer/ @@ -217,6 +221,7 @@ ChainConfig: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ~/zkbnb-deploy/zkbnb/service/cronjob/sender/etc/sender.yaml cd ~/zkbnb-deploy/zkbnb/service/cronjob/sender/ @@ -247,6 +252,7 @@ LogConf: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ~/zkbnb-deploy/zkbnb/service/rpc/globalRPC/etc/config.yaml cd ~/zkbnb-deploy/zkbnb/service/rpc/globalRPC/ @@ -279,6 +285,7 @@ LogConf: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ~/zkbnb-deploy/zkbnb/service/api/app/etc/app.yaml cd ~/zkbnb-deploy/zkbnb/service/api/app diff --git a/deployment/docker-compose/docker-compose.sh b/deployment/docker-compose/docker-compose.sh index 98d926092..0fc8c25bb 100644 --- a/deployment/docker-compose/docker-compose.sh +++ b/deployment/docker-compose/docker-compose.sh @@ -61,6 +61,7 @@ LogConf: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ${CONFIG_PATH}/witness.yaml echo -e " @@ -104,6 +105,7 @@ BlockConfig: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 " > ${CONFIG_PATH}/committer.yaml echo -e " diff --git a/docs/tree/recovery.md b/docs/tree/recovery.md index a3f323d42..5644b7a4a 100644 --- a/docs/tree/recovery.md +++ b/docs/tree/recovery.md @@ -17,6 +17,7 @@ CacheRedis: TreeDB: Driver: leveldb + AssetTreeCacheSize: 512000 LevelDBOption: File: /tmp/test ``` diff --git a/service/committer/etc/config.yaml.example b/service/committer/etc/config.yaml.example index 4d8123317..bd08cf5b1 100644 --- a/service/committer/etc/config.yaml.example +++ b/service/committer/etc/config.yaml.example @@ -12,3 +12,4 @@ BlockConfig: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 diff --git a/service/monitor/etc/config.yaml.example b/service/monitor/etc/config.yaml.example index ac27f5e8b..0ef798c93 100644 --- a/service/monitor/etc/config.yaml.example +++ b/service/monitor/etc/config.yaml.example @@ -20,4 +20,5 @@ LogConf: Level: info TreeDB: - Driver: memorydb \ No newline at end of file + Driver: memorydb + AssetTreeCacheSize: 512000 \ No newline at end of file diff --git a/service/witness/config/config.go b/service/witness/config/config.go index b2dbc2983..dfcef2a5f 100644 --- a/service/witness/config/config.go +++ b/service/witness/config/config.go @@ -15,7 +15,8 @@ type Config struct { //nolint:staticcheck LevelDBOption tree.LevelDBOption `json:",optional"` //nolint:staticcheck - RedisDBOption tree.RedisDBOption `json:",optional"` + RedisDBOption tree.RedisDBOption `json:",optional"` + AssetTreeCacheSize int } LogConf logx.LogConf } diff --git a/service/witness/etc/config.yaml.example b/service/witness/etc/config.yaml.example index d776f5740..a3e64efb6 100644 --- a/service/witness/etc/config.yaml.example +++ b/service/witness/etc/config.yaml.example @@ -5,6 +5,7 @@ Postgres: TreeDB: Driver: memorydb + AssetTreeCacheSize: 512000 LogConf: ServiceName: witness diff --git a/service/witness/witness/witness.go b/service/witness/witness/witness.go index 885c55fb5..612ed27ca 100644 --- a/service/witness/witness/witness.go +++ b/service/witness/witness/witness.go @@ -110,6 +110,7 @@ func (w *Witness) initState() error { w.accountHistoryModel, witnessHeight, treeCtx, + w.config.TreeDB.AssetTreeCacheSize, ) // the blockHeight depends on the proof start position if err != nil { diff --git a/tools/recovery/etc/config.yaml.example b/tools/recovery/etc/config.yaml.example index d05250060..c71f0d629 100644 --- a/tools/recovery/etc/config.yaml.example +++ b/tools/recovery/etc/config.yaml.example @@ -7,4 +7,5 @@ CacheRedis: Type: node TreeDB: - Driver: memorydb \ No newline at end of file + Driver: memorydb + AssetTreeCacheSize: 512000 \ No newline at end of file diff --git a/tools/recovery/internal/config/config.go b/tools/recovery/internal/config/config.go index bd6c7c342..64f646719 100644 --- a/tools/recovery/internal/config/config.go +++ b/tools/recovery/internal/config/config.go @@ -17,7 +17,8 @@ type Config struct { //nolint:staticcheck LevelDBOption tree.LevelDBOption `json:",optional"` //nolint:staticcheck - RedisDBOption tree.RedisDBOption `json:",optional"` + RedisDBOption tree.RedisDBOption `json:",optional"` + AssetTreeCacheSize int } LogConf logx.LogConf } diff --git a/tools/recovery/recovery.go b/tools/recovery/recovery.go index 6a2a3fc2b..3722c80b9 100644 --- a/tools/recovery/recovery.go +++ b/tools/recovery/recovery.go @@ -48,6 +48,7 @@ func RecoveryTreeDB( ctx.AccountHistoryModel, blockHeight, treeCtx, + c.TreeDB.AssetTreeCacheSize, ) if err != nil { logx.Error("InitMerkleTree error:", err) diff --git a/tree/account_tree.go b/tree/account_tree.go index d9d4e07ff..2b4c53e22 100644 --- a/tree/account_tree.go +++ b/tree/account_tree.go @@ -40,6 +40,7 @@ func InitAccountTree( accountHistoryModel account.AccountHistoryModel, blockHeight int64, ctx *Context, + assetCacheSize int, ) ( accountTree bsmt.SparseMerkleTree, accountAssetTrees *AssetTreeCache, err error, ) { @@ -52,10 +53,10 @@ func InitAccountTree( opts := ctx.Options(blockHeight) // init account state trees - accountAssetTrees = NewLazyTreeCache(types.AssetTreeCacheSize, accountNums-1, func(index int64) bsmt.SparseMerkleTree { + accountAssetTrees = NewLazyTreeCache(assetCacheSize, accountNums-1, blockHeight, func(index, block int64) bsmt.SparseMerkleTree { tree, err := bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), SetNamespace(ctx, accountAssetNamespace(index)), AssetTreeHeight, NilAccountAssetNodeHash, - opts...) + ctx.Options(block)...) if err != nil { logx.Errorf("unable to create new tree by assets: %s", err.Error()) panic(err.Error()) @@ -255,24 +256,6 @@ func AccountToNode( return hashVal, nil } -func NewEmptyAccountAssetTreeFunc( - ctx *Context, - blockHeight uint64, -) func(index int64) bsmt.SparseMerkleTree { - return func(index int64) bsmt.SparseMerkleTree { - tree, err := bsmt.NewBASSparseMerkleTree( - bsmt.NewHasher(mimc.NewMiMC()), - SetNamespace(ctx, accountAssetNamespace(index)), - AssetTreeHeight, NilAccountAssetNodeHash, - ctx.Options(int64(blockHeight))...) - if err != nil { - logx.Errorf("unable to create new tree by assets: %s", err.Error()) - panic(err.Error()) - } - return tree - } -} - func NewMemAccountAssetTree() (tree bsmt.SparseMerkleTree, err error) { return bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), memory.NewMemoryDB(), AssetTreeHeight, NilAccountAssetNodeHash) diff --git a/tree/asset_tree_cache.go b/tree/asset_tree_cache.go index e9cb591b2..7ec8cae73 100644 --- a/tree/asset_tree_cache.go +++ b/tree/asset_tree_cache.go @@ -9,8 +9,9 @@ import ( // Lazy init cache for asset trees type AssetTreeCache struct { - initFunction func(index int64) bsmt.SparseMerkleTree + initFunction func(index, block int64) bsmt.SparseMerkleTree nextAccountNumber int64 + blockNumber int64 mainLock sync.RWMutex changes map[int64]bool changesLock sync.RWMutex @@ -20,19 +21,21 @@ type AssetTreeCache struct { // Creates new AssetTreeCache // maxSize defines the maximum size of currently initialized trees // accountNumber defines the number of accounts to create/or next index for new account -func NewLazyTreeCache(maxSize int, accountNumber int64, f func(index int64) bsmt.SparseMerkleTree) *AssetTreeCache { - cache := AssetTreeCache{initFunction: f, nextAccountNumber: accountNumber, changes: make(map[int64]bool, maxSize*10)} +func NewLazyTreeCache(maxSize int, accountNumber int64, blockNumber int64, f func(index, block int64) bsmt.SparseMerkleTree) *AssetTreeCache { + cache := AssetTreeCache{initFunction: f, nextAccountNumber: accountNumber, blockNumber: blockNumber, changes: make(map[int64]bool, maxSize*10)} cache.treeCache, _ = lru.NewWithEvict(maxSize, cache.onDelete) return &cache } -// Updates current cache with new(updated) init function and with latest account index -func (c *AssetTreeCache) UpdateCache(accountNumber int64, f func(index int64) bsmt.SparseMerkleTree) { +// Updates current cache with new block number and with latest account index +func (c *AssetTreeCache) UpdateCache(accountNumber, latestBlock int64) { c.mainLock.Lock() - c.initFunction = f if c.nextAccountNumber < accountNumber { c.nextAccountNumber = accountNumber } + if c.blockNumber < latestBlock { + c.blockNumber = latestBlock + } c.mainLock.Unlock() } @@ -46,7 +49,7 @@ func (c *AssetTreeCache) GetNextAccountIndex() int64 { // Returns asset tree based on account index func (c *AssetTreeCache) Get(i int64) (tree bsmt.SparseMerkleTree) { c.mainLock.RLock() - c.treeCache.ContainsOrAdd(i, c.initFunction(i)) + c.treeCache.ContainsOrAdd(i, c.initFunction(i, c.blockNumber)) c.mainLock.RUnlock() if tmpTree, ok := c.treeCache.Get(i); ok { tree = tmpTree.(bsmt.SparseMerkleTree) @@ -55,7 +58,6 @@ func (c *AssetTreeCache) Get(i int64) (tree bsmt.SparseMerkleTree) { } // Returns slice of indexes of asset trees that were changned -// and resets cache of the marked changes of asset trees. func (c *AssetTreeCache) GetChanges() []int64 { c.mainLock.Lock() c.changesLock.Lock() @@ -71,11 +73,16 @@ func (c *AssetTreeCache) GetChanges() []int64 { for key := range c.changes { ret = append(ret, key) } - // Cleans map - c.changes = make(map[int64]bool, len(c.changes)) return ret } +// Cleans all saved tree changes in the cache +func (c *AssetTreeCache) CleanChanges() { + c.changesLock.Lock() + c.changes = make(map[int64]bool, len(c.changes)) + c.changesLock.Unlock() +} + // Internal method to that marks if changes happend to tree eviced from LRU func (c *AssetTreeCache) onDelete(k, v interface{}) { c.changesLock.Lock() diff --git a/tree/util.go b/tree/util.go index 2d6fc0a3b..c183e4f75 100644 --- a/tree/util.go +++ b/tree/util.go @@ -123,6 +123,7 @@ func CommitTrees( nftTree bsmt.SparseMerkleTree) error { assetTreeChanges := assetTrees.GetChanges() + defer assetTrees.CleanChanges() totalTask := len(assetTreeChanges) + 3 errChan := make(chan error, totalTask) defer close(errChan) @@ -212,6 +213,7 @@ func RollBackTrees( nftTree bsmt.SparseMerkleTree) error { assetTreeChanges := assetTrees.GetChanges() + defer assetTrees.CleanChanges() totalTask := len(assetTreeChanges) + 3 errChan := make(chan error, totalTask) defer close(errChan) diff --git a/types/constant.go b/types/constant.go index c3dd2a16b..92ef0863c 100644 --- a/types/constant.go +++ b/types/constant.go @@ -48,8 +48,6 @@ const ( BNBAssetId = 0 BNBDecimals = "1000000000000000000" - - AssetTreeCacheSize = 256 ) var ( From 1770831dbbbc32cd5f6dee38338785fa071a7b28 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Thu, 29 Sep 2022 16:08:04 +0800 Subject: [PATCH 07/23] refactor: prune amm related txs and types (#205) --- README.md | 15 +- common/chain/balance_helper.go | 23 - common/chain/liquidity_helper.go | 152 ---- common/chain/liquidity_helper_test.go | 83 -- common/chain/pubdata_helper.go | 44 - common/pack.go | 8 - common/prove/add_liquidity.go | 89 -- common/prove/create_pair.go | 51 -- common/prove/proof_keys.go | 2 +- common/prove/remove_liquidity.go | 99 --- common/prove/swap.go | 79 -- common/prove/types.go | 13 +- common/prove/update_pairrate.go | 49 -- common/prove/witness_helper.go | 168 +--- common/prove/witness_test.go | 24 +- core/blockchain.go | 31 +- core/executor/add_liquidity_executor.go | 549 ------------ core/executor/atomic_match_executor.go | 16 +- core/executor/base_executor.go | 10 - core/executor/cancel_offer_executor.go | 3 - core/executor/create_collection_executor.go | 2 - core/executor/create_pair_executor.go | 153 ---- core/executor/deposit_executor.go | 1 - core/executor/deposit_nft_executor.go | 1 - core/executor/executor.go | 10 - core/executor/full_exit_executor.go | 1 - core/executor/full_exit_nft_executor.go | 1 - core/executor/mint_nft_executor.go | 3 - core/executor/remove_liquidity_executor.go | 523 ------------ core/executor/swap_executor.go | 457 ---------- core/executor/transfer_executor.go | 8 +- core/executor/transfer_nft_executor.go | 3 - core/executor/update_pair_rate_executor.go | 171 ---- core/executor/withdraw_executor.go | 6 +- core/executor/withdraw_nft_executor.go | 3 - core/statedb/chaindb.go | 29 +- core/statedb/state_cache.go | 47 +- core/statedb/statedb.go | 204 +---- dao/block/block.go | 16 +- dao/dbcache/cache.go | 13 +- dao/liquidity/liquidity.go | 123 --- dao/liquidity/liquidity_history.go | 118 --- dao/tx/tx.go | 1 - docs/api_reference.md | 153 ---- docs/assets/storage_layout.png | Bin 63310 -> 42433 bytes docs/protocol.md | 799 +----------------- docs/readme.md | 2 - docs/storage_layout.md | 7 - docs/technology.md | 2 +- docs/wallets.md | 46 - go.mod | 4 +- go.sum | 9 +- .../internal/fetcher/state/fetcher.go | 45 +- .../handler/pair/getlpvaluehandler.go | 29 - .../internal/handler/pair/getpairhandler.go | 29 - .../internal/handler/pair/getpairshandler.go | 22 - .../handler/pair/getswapamounthandler.go | 29 - service/apiserver/internal/handler/routes.go | 26 - .../internal/logic/account/getaccountlogic.go | 10 +- .../internal/logic/pair/getlpvaluelogic.go | 80 -- .../internal/logic/pair/getpairlogic.go | 66 -- .../internal/logic/pair/getpairslogic.go | 72 -- .../internal/logic/pair/getswapamountlogic.go | 73 -- .../logic/transaction/getnextnoncelogic.go | 2 +- .../internal/logic/transaction/sendtxlogic.go | 3 +- .../internal/logic/utils/converter.go | 1 - .../apiserver/internal/svc/servicecontext.go | 50 +- service/apiserver/server.api | 86 -- service/apiserver/test/getlpvalue_test.go | 77 -- service/apiserver/test/getpair_test.go | 66 -- service/apiserver/test/getpairs_test.go | 68 -- service/apiserver/test/getswapamount_test.go | 78 -- service/committer/committer/committer.go | 24 +- .../monitor/monitor_governance_blocks.go | 2 +- .../monitor/monitor_priority_requests.go | 25 - service/monitor/monitor/types.go | 12 +- service/witness/witness/witness.go | 57 +- tools/dbinitializer/main.go | 76 +- tools/recovery/internal/svc/servicecontext.go | 17 +- tools/recovery/recovery.go | 9 - tree/account_tree.go | 5 +- tree/hash_test.go | 11 + tree/liquidity_tree.go | 140 --- tree/types.go | 24 +- tree/util.go | 109 +-- types/account.go | 17 +- types/code.go | 55 +- types/constant.go | 4 +- types/liquidity.go | 98 --- types/system.go | 3 +- types/tx.go | 57 -- 91 files changed, 284 insertions(+), 5797 deletions(-) delete mode 100644 common/chain/liquidity_helper.go delete mode 100644 common/chain/liquidity_helper_test.go delete mode 100644 common/prove/add_liquidity.go delete mode 100644 common/prove/create_pair.go delete mode 100644 common/prove/remove_liquidity.go delete mode 100644 common/prove/swap.go delete mode 100644 common/prove/update_pairrate.go delete mode 100644 core/executor/add_liquidity_executor.go delete mode 100644 core/executor/create_pair_executor.go delete mode 100644 core/executor/remove_liquidity_executor.go delete mode 100644 core/executor/swap_executor.go delete mode 100644 core/executor/update_pair_rate_executor.go delete mode 100644 dao/liquidity/liquidity.go delete mode 100644 dao/liquidity/liquidity_history.go delete mode 100644 service/apiserver/internal/handler/pair/getlpvaluehandler.go delete mode 100644 service/apiserver/internal/handler/pair/getpairhandler.go delete mode 100644 service/apiserver/internal/handler/pair/getpairshandler.go delete mode 100644 service/apiserver/internal/handler/pair/getswapamounthandler.go delete mode 100644 service/apiserver/internal/logic/pair/getlpvaluelogic.go delete mode 100644 service/apiserver/internal/logic/pair/getpairlogic.go delete mode 100644 service/apiserver/internal/logic/pair/getpairslogic.go delete mode 100644 service/apiserver/internal/logic/pair/getswapamountlogic.go delete mode 100644 service/apiserver/test/getlpvalue_test.go delete mode 100644 service/apiserver/test/getpair_test.go delete mode 100644 service/apiserver/test/getpairs_test.go delete mode 100644 service/apiserver/test/getswapamount_test.go create mode 100644 tree/hash_test.go delete mode 100644 tree/liquidity_tree.go delete mode 100644 types/liquidity.go diff --git a/README.md b/README.md index b993db286..eac295576 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,6 @@ ZkBNB achieves the following goals: cryptographic. Users do not have to trust any third parties or keep monitoring the Rollup blocks in order to prevent fraud. - **L1<>L2 Communication**. BNB, and BEP20/BEP721/BEP1155 created on BSC or ZkBNB can flow freely between BSC and ZkBNB. -- **Built-in instant AMM swap**. It allows digital assets to be traded without permission and automatically by using - liquidity pools. - **Built-in NFT marketplace**. Developer can build marketplace for crypto collectibles and non-fungible tokens (NFTs) out of box on ZkBNB. - **Fast transaction speed and faster finality**. @@ -35,7 +33,6 @@ ZkBNB starts its development based on [Zecrey](https://github.com/bnb-chain/zecr - [Key Features](#Key-Features) + [Digital Asset Management](#Digital-Asset-Management) + [NFT Management and Marketplace](#NFT-Management-and-Marketplace) - + [AMM Exchange](#AMM-Exchange) + [Native Name Service](#Native-Name-Service) + [Seamless L1 Wallet Management](#Seamless-L1-Wallet-Management) @@ -59,7 +56,7 @@ ZkBNB starts its development based on [Zecrey](https://github.com/bnb-chain/zecr - **prover**. Prover generates cryptographic proof based on the witness materials. - **sender**. The sender rollups the compressed l2 blocks to L1, and submit proof to verify it. - **api server**. The api server is the access endpoints for most users, it provides rich data, including - digital assets, blocks, transactions, swap info, gas fees. + digital assets, blocks, transactions, gas fees. - **recovery**. A tool to recover the sparse merkle tree in kv-rocks based on the state world in postgresql. @@ -105,16 +102,6 @@ being sent to the ZkBNB. Once the offer is matched, an **AtomicMatch** transacti will be sent to ZkBNB to make the trade happen. Users can also cancel an offer manually by sending a cancel offer transaction to disable the backend cached offer. -### AMM Exchange - -Automated market makers (AMM) are decentralized exchanges that pool liquidity from users and price the assets within -the pool using algorithms. - -ZkBNB follows the similar mechanic as [UniSwap V2](https://docs.uniswap.org/protocol/V2/concepts/protocol-overview/how-uniswap-works). -Anyone can become a liquidity provider (LP) for a pool by depositing an equivalent value of each underlying token in -return for pool tokens. The different from UniSwap is that the LP token on ZkBNB can not transfer or trade. Users can -simply list a swap pair by calling the rollup contract on BSC. - ### Native Name Service No more copying and pasting long addresses on ZkBNB. Every account on ZkBNB gets its short name, user can use that to store funds and receive any cryptocurrency, token, or NFT. diff --git a/common/chain/balance_helper.go b/common/chain/balance_helper.go index 056818fe5..676957ff4 100644 --- a/common/chain/balance_helper.go +++ b/common/chain/balance_helper.go @@ -36,7 +36,6 @@ func ComputeNewBalance(assetType int64, balance string, balanceDelta string) (ne return "", err } assetInfo.Balance = ffmath.Add(assetInfo.Balance, assetDelta.Balance) - assetInfo.LpAmount = ffmath.Add(assetInfo.LpAmount, assetDelta.LpAmount) if assetDelta.OfferCanceledOrFinalized == nil { assetDelta.OfferCanceledOrFinalized = types.ZeroBigInt } @@ -44,28 +43,6 @@ func ComputeNewBalance(assetType int64, balance string, balanceDelta string) (ne assetInfo.OfferCanceledOrFinalized = assetDelta.OfferCanceledOrFinalized } newBalance = assetInfo.String() - case types.LiquidityAssetType: - // balance: LiquidityInfo - liquidityInfo, err := types.ParseLiquidityInfo(balance) - if err != nil { - return "", err - } - deltaLiquidity, err := types.ParseLiquidityInfo(balanceDelta) - if err != nil { - return "", err - } - liquidityInfo.AssetAId = deltaLiquidity.AssetAId - liquidityInfo.AssetBId = deltaLiquidity.AssetBId - liquidityInfo.AssetA = ffmath.Add(liquidityInfo.AssetA, deltaLiquidity.AssetA) - liquidityInfo.AssetB = ffmath.Add(liquidityInfo.AssetB, deltaLiquidity.AssetB) - liquidityInfo.LpAmount = ffmath.Add(liquidityInfo.LpAmount, deltaLiquidity.LpAmount) - if deltaLiquidity.KLast.Cmp(types.ZeroBigInt) != 0 { - liquidityInfo.KLast = deltaLiquidity.KLast - } - liquidityInfo.FeeRate = deltaLiquidity.FeeRate - liquidityInfo.TreasuryAccountIndex = deltaLiquidity.TreasuryAccountIndex - liquidityInfo.TreasuryRate = deltaLiquidity.TreasuryRate - newBalance = liquidityInfo.String() case types.NftAssetType: // just set the old one as the new one newBalance = balanceDelta diff --git a/common/chain/liquidity_helper.go b/common/chain/liquidity_helper.go deleted file mode 100644 index 14f725db1..000000000 --- a/common/chain/liquidity_helper.go +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package chain - -import ( - "errors" - "math/big" - - "github.com/bnb-chain/zkbnb-crypto/ffmath" - "github.com/bnb-chain/zkbnb-crypto/util" - "github.com/bnb-chain/zkbnb/common" - "github.com/bnb-chain/zkbnb/types" -) - -func ComputeEmptyLpAmount( - assetAAmount *big.Int, - assetBAmount *big.Int, -) (lpAmount *big.Int, err error) { - lpSquare := ffmath.Multiply(assetAAmount, assetBAmount) - lpFloat := ffmath.FloatSqrt(ffmath.IntToFloat(lpSquare)) - lpAmount, err = common.CleanPackedAmount(ffmath.FloatToInt(lpFloat)) - if err != nil { - return nil, err - } - return lpAmount, nil -} - -func ComputeLpAmount(liquidityInfo *types.LiquidityInfo, assetAAmount *big.Int) (lpAmount *big.Int, err error) { - // lp = assetAAmount / poolA * LpAmount - sLp, err := ComputeSLp(liquidityInfo.AssetA, liquidityInfo.AssetB, liquidityInfo.KLast, liquidityInfo.FeeRate, liquidityInfo.TreasuryRate) - if err != nil { - return nil, err - } - poolLpAmount := ffmath.Sub(liquidityInfo.LpAmount, sLp) - lpAmount, err = common.CleanPackedAmount(ffmath.Div(ffmath.Multiply(assetAAmount, poolLpAmount), liquidityInfo.AssetA)) - if err != nil { - return nil, err - } - return lpAmount, nil -} - -func ComputeRemoveLiquidityAmount(liquidityInfo *types.LiquidityInfo, lpAmount *big.Int) (assetAAmount, assetBAmount *big.Int, err error) { - sLp, err := ComputeSLp(liquidityInfo.AssetA, liquidityInfo.AssetB, liquidityInfo.KLast, liquidityInfo.FeeRate, liquidityInfo.TreasuryRate) - if err != nil { - return nil, nil, err - } - lpAmount, err = common.CleanPackedAmount(lpAmount) - if err != nil { - return nil, nil, err - } - poolLp := ffmath.Sub(liquidityInfo.LpAmount, sLp) - assetAAmount = ffmath.Multiply(lpAmount, liquidityInfo.AssetA) - assetAAmount, _ = util.CleanPackedAmount(ffmath.Div(assetAAmount, poolLp)) - assetBAmount = ffmath.Multiply(lpAmount, liquidityInfo.AssetB) - assetBAmount, _ = util.CleanPackedAmount(ffmath.Div(assetBAmount, poolLp)) - return assetAAmount, assetBAmount, nil -} - -func ComputeDelta( - assetAAmount *big.Int, - assetBAmount *big.Int, - assetAId int64, assetBId int64, assetId int64, isFrom bool, - deltaAmount *big.Int, - feeRate int64, -) (assetAmount *big.Int, toAssetId int64, err error) { - - if isFrom { - if assetAId == assetId { - delta, err := ComputeInputPrice(assetAAmount, assetBAmount, deltaAmount, feeRate) - if err != nil { - return nil, 0, err - } - return delta, assetBId, nil - } else if assetBId == assetId { - delta, err := ComputeInputPrice(assetBAmount, assetAAmount, deltaAmount, feeRate) - if err != nil { - return nil, 0, err - } - return delta, assetAId, nil - } else { - return types.ZeroBigInt, 0, errors.New("[ComputeDelta]: invalid asset id") - } - } else { - if assetAId == assetId { - delta, err := ComputeOutputPrice(assetAAmount, assetBAmount, deltaAmount, feeRate) - if err != nil { - return nil, 0, err - } - return delta, assetBId, nil - } else if assetBId == assetId { - delta, err := ComputeOutputPrice(assetBAmount, assetAAmount, deltaAmount, feeRate) - if err != nil { - return nil, 0, err - } - return delta, assetAId, nil - } else { - return types.ZeroBigInt, 0, errors.New("[ComputeDelta]: invalid asset id") - } - } -} - -// ComputeInputPrice InputPrice = (9970 * deltaX * y) / (10000 * x + 9970 * deltaX) -func ComputeInputPrice(x *big.Int, y *big.Int, inputX *big.Int, feeRate int64) (*big.Int, error) { - rFeeR := big.NewInt(types.FeeRateBase - feeRate) - res, err := util.CleanPackedAmount(ffmath.Div(ffmath.Multiply(rFeeR, ffmath.Multiply(inputX, y)), ffmath.Add(ffmath.Multiply(big.NewInt(types.FeeRateBase), x), ffmath.Multiply(rFeeR, inputX)))) - if err != nil { - return nil, err - } - return res, nil -} - -// ComputeOutputPrice OutputPrice = (10000 * x * deltaY) / (9970 * (y - deltaY)) + 1 -func ComputeOutputPrice(x *big.Int, y *big.Int, inputY *big.Int, feeRate int64) (*big.Int, error) { - rFeeR := big.NewInt(types.FeeRateBase - feeRate) - res, err := common.CleanPackedAmount(ffmath.Add(ffmath.Div(ffmath.Multiply(big.NewInt(types.FeeRateBase), ffmath.Multiply(x, inputY)), ffmath.Multiply(rFeeR, ffmath.Sub(y, inputY))), big.NewInt(1))) - if err != nil { - return nil, err - } - return res, nil -} - -func ComputeSLp(poolA, poolB *big.Int, kLast *big.Int, feeRate, treasuryRate int64) (*big.Int, error) { - kCurrent := ffmath.Multiply(poolA, poolB) - if kCurrent.Cmp(types.ZeroBigInt) == 0 { - return types.ZeroBigInt, nil - } - kCurrent.Sqrt(kCurrent) - kLast.Sqrt(kLast) - l := ffmath.Multiply(ffmath.Sub(kCurrent, kLast), big.NewInt(types.FeeRateBase)) - r := ffmath.Multiply(ffmath.Sub(ffmath.Multiply(big.NewInt(types.FeeRateBase), ffmath.Div(big.NewInt(feeRate), big.NewInt(treasuryRate))), big.NewInt(types.FeeRateBase)), kCurrent) - r = ffmath.Add(r, ffmath.Multiply(big.NewInt(types.FeeRateBase), kLast)) - res, err := common.CleanPackedAmount(ffmath.Div(l, r)) - if err != nil { - return nil, err - } - return res, nil -} diff --git a/common/chain/liquidity_helper_test.go b/common/chain/liquidity_helper_test.go deleted file mode 100644 index a56479e8a..000000000 --- a/common/chain/liquidity_helper_test.go +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package chain - -import ( - "math/big" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/bnb-chain/zkbnb/types" -) - -func TestComputeDeltaY(t *testing.T) { - poolA := big.NewInt(1000) - poolB := big.NewInt(1000) - deltaY, assetId, err := ComputeDelta( - poolA, poolB, - 0, 2, 0, false, big.NewInt(500), - 30, - ) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, deltaY.String(), "1004") - assert.Equal(t, assetId, int64(2)) -} - -func TestComputeRemoveLiquidityAmount(t *testing.T) { - liquidityInfo := &types.LiquidityInfo{ - PairIndex: 0, - AssetAId: 0, - AssetA: big.NewInt(99901), - AssetBId: 2, - AssetB: big.NewInt(100100), - LpAmount: big.NewInt(100000), - KLast: big.NewInt(10000000000), - FeeRate: 30, - TreasuryAccountIndex: 0, - TreasuryRate: 5, - } - aAmount, bAmount, _ := ComputeRemoveLiquidityAmount( - liquidityInfo, - big.NewInt(100), - ) - assert.Equal(t, aAmount.Int64(), int64(99)) - assert.Equal(t, bAmount.Int64(), int64(100)) -} - -func TestComputeInputPrice(t *testing.T) { - poolA := big.NewInt(1000) - poolB := big.NewInt(1000) - deltaY, _ := ComputeInputPrice( - poolA, poolB, - big.NewInt(500), 30, - ) - assert.Equal(t, deltaY.Int64(), int64(332)) -} - -func TestComputeOutputPrice(t *testing.T) { - poolA := big.NewInt(1000) - poolB := big.NewInt(1000) - deltaY, _ := ComputeOutputPrice( - poolA, poolB, - big.NewInt(500), 30, - ) - assert.Equal(t, deltaY.Int64(), int64(1004)) -} diff --git a/common/chain/pubdata_helper.go b/common/chain/pubdata_helper.go index 9d8d6d33f..fa2fb8dc9 100644 --- a/common/chain/pubdata_helper.go +++ b/common/chain/pubdata_helper.go @@ -61,50 +61,6 @@ func ParseRegisterZnsPubData(pubData []byte) (tx *txtypes.RegisterZnsTxInfo, err return tx, nil } -func ParseCreatePairPubData(pubData []byte) (tx *txtypes.CreatePairTxInfo, err error) { - if len(pubData) != types.CreatePairPubDataSize { - return nil, errors.New("[ParseCreatePairPubData] invalid size") - } - offset := 0 - offset, txType := common2.ReadUint8(pubData, offset) - offset, pairIndex := common2.ReadUint16(pubData, offset) - offset, assetAId := common2.ReadUint16(pubData, offset) - offset, assetBId := common2.ReadUint16(pubData, offset) - offset, feeRate := common2.ReadUint16(pubData, offset) - offset, treasuryAccountIndex := common2.ReadUint32(pubData, offset) - _, treasuryRate := common2.ReadUint16(pubData, offset) - tx = &txtypes.CreatePairTxInfo{ - TxType: txType, - PairIndex: int64(pairIndex), - AssetAId: int64(assetAId), - AssetBId: int64(assetBId), - FeeRate: int64(feeRate), - TreasuryAccountIndex: int64(treasuryAccountIndex), - TreasuryRate: int64(treasuryRate), - } - return tx, nil -} - -func ParseUpdatePairRatePubData(pubData []byte) (tx *txtypes.UpdatePairRateTxInfo, err error) { - if len(pubData) != types.UpdatePairRatePubdataSize { - return nil, errors.New("[ParseUpdatePairRatePubData] invalid size") - } - offset := 0 - offset, txType := common2.ReadUint8(pubData, offset) - offset, pairIndex := common2.ReadUint16(pubData, offset) - offset, feeRate := common2.ReadUint16(pubData, offset) - offset, treasuryAccountIndex := common2.ReadUint32(pubData, offset) - _, treasuryRate := common2.ReadUint16(pubData, offset) - tx = &txtypes.UpdatePairRateTxInfo{ - TxType: txType, - PairIndex: int64(pairIndex), - FeeRate: int64(feeRate), - TreasuryAccountIndex: int64(treasuryAccountIndex), - TreasuryRate: int64(treasuryRate), - } - return tx, nil -} - func ParseDepositPubData(pubData []byte) (tx *txtypes.DepositTxInfo, err error) { /* struct Deposit { diff --git a/common/pack.go b/common/pack.go index 945a98e79..613e5d386 100644 --- a/common/pack.go +++ b/common/pack.go @@ -11,15 +11,7 @@ func ToPackedAmount(amount *big.Int) (res int64, err error) { return util.ToPackedAmount(amount) } -func CleanPackedAmount(amount *big.Int) (nAmount *big.Int, err error) { - return util.CleanPackedAmount(amount) -} - // ToPackedFee : convert big int to 16 bit, 5 bits for 10^x, 11 bits for a * 10^x func ToPackedFee(amount *big.Int) (res int64, err error) { return util.ToPackedFee(amount) } - -func CleanPackedFee(amount *big.Int) (nAmount *big.Int, err error) { - return util.CleanPackedFee(amount) -} diff --git a/common/prove/add_liquidity.go b/common/prove/add_liquidity.go deleted file mode 100644 index c230057f4..000000000 --- a/common/prove/add_liquidity.go +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package prove - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254/twistededwards/eddsa" - - cryptoTypes "github.com/bnb-chain/zkbnb-crypto/circuit/types" - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - "github.com/bnb-chain/zkbnb/common" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -func (w *WitnessHelper) constructAddLiquidityTxWitness(witness *TxWitness, oTx *tx.Tx) (*TxWitness, error) { - txInfo, err := types.ParseAddLiquidityTxInfo(oTx.TxInfo) - if err != nil { - return nil, err - } - cryptoTxInfo, err := toCryptoAddLiquidityTx(txInfo) - if err != nil { - return nil, err - } - witness.AddLiquidityTxInfo = cryptoTxInfo - witness.ExpiredAt = txInfo.ExpiredAt - witness.Signature = new(eddsa.Signature) - _, err = witness.Signature.SetBytes(txInfo.Sig) - if err != nil { - return nil, err - } - return witness, nil -} - -func toCryptoAddLiquidityTx(txInfo *txtypes.AddLiquidityTxInfo) (info *cryptoTypes.AddLiquidityTx, err error) { - packedAAmount, err := common.ToPackedAmount(txInfo.AssetAAmount) - if err != nil { - return nil, err - } - packedBAmount, err := common.ToPackedAmount(txInfo.AssetBAmount) - if err != nil { - return nil, err - } - packedLpAmount, err := common.ToPackedAmount(txInfo.LpAmount) - if err != nil { - return nil, err - } - packedTreasuryAmount, err := common.ToPackedAmount(txInfo.TreasuryAmount) - if err != nil { - return nil, err - } - packedKLast, err := common.ToPackedAmount(txInfo.KLast) - if err != nil { - return nil, err - } - packedFee, err := common.ToPackedFee(txInfo.GasFeeAssetAmount) - if err != nil { - return nil, err - } - info = &cryptoTypes.AddLiquidityTx{ - FromAccountIndex: txInfo.FromAccountIndex, - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetAId, - AssetAAmount: packedAAmount, - AssetBId: txInfo.AssetBId, - AssetBAmount: packedBAmount, - LpAmount: packedLpAmount, - KLast: packedKLast, - TreasuryAmount: packedTreasuryAmount, - GasAccountIndex: txInfo.GasAccountIndex, - GasFeeAssetId: txInfo.GasFeeAssetId, - GasFeeAssetAmount: packedFee, - } - return info, nil -} diff --git a/common/prove/create_pair.go b/common/prove/create_pair.go deleted file mode 100644 index 827ae8144..000000000 --- a/common/prove/create_pair.go +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package prove - -import ( - cryptoTypes "github.com/bnb-chain/zkbnb-crypto/circuit/types" - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -func (w *WitnessHelper) constructCreatePairTxWitness(cryptoTx *TxWitness, oTx *tx.Tx) (*TxWitness, error) { - txInfo, err := types.ParseCreatePairTxInfo(oTx.TxInfo) - if err != nil { - return nil, err - } - cryptoTxInfo, err := toCryptoCreatePairTx(txInfo) - if err != nil { - return nil, err - } - cryptoTx.CreatePairTxInfo = cryptoTxInfo - cryptoTx.Signature = cryptoTypes.EmptySignature() - return cryptoTx, nil -} - -func toCryptoCreatePairTx(txInfo *txtypes.CreatePairTxInfo) (info *cryptoTypes.CreatePairTx, err error) { - info = &cryptoTypes.CreatePairTx{ - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetAId, - AssetBId: txInfo.AssetBId, - FeeRate: txInfo.FeeRate, - TreasuryAccountIndex: txInfo.TreasuryAccountIndex, - TreasuryRate: txInfo.TreasuryRate, - } - return info, nil -} diff --git a/common/prove/proof_keys.go b/common/prove/proof_keys.go index 809176fa2..a93fd0843 100644 --- a/common/prove/proof_keys.go +++ b/common/prove/proof_keys.go @@ -64,7 +64,7 @@ func GenerateProof( if err != nil { return proof, err } - proof, err = groth16.Prove(r1cs, provingKey, witness, backend.WithHints(types.Keccak256, types.ComputeSLp)) + proof, err = groth16.Prove(r1cs, provingKey, witness, backend.WithHints(types.Keccak256)) if err != nil { return proof, err } diff --git a/common/prove/remove_liquidity.go b/common/prove/remove_liquidity.go deleted file mode 100644 index 7768d3c99..000000000 --- a/common/prove/remove_liquidity.go +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package prove - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254/twistededwards/eddsa" - - cryptoTypes "github.com/bnb-chain/zkbnb-crypto/circuit/types" - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - "github.com/bnb-chain/zkbnb/common" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -func (w *WitnessHelper) constructRemoveLiquidityTxWitness(cryptoTx *TxWitness, oTx *tx.Tx) (*TxWitness, error) { - txInfo, err := types.ParseRemoveLiquidityTxInfo(oTx.TxInfo) - if err != nil { - return nil, err - } - cryptoTxInfo, err := toCryptoRemoveLiquidityTx(txInfo) - if err != nil { - return nil, err - } - cryptoTx.RemoveLiquidityTxInfo = cryptoTxInfo - cryptoTx.ExpiredAt = txInfo.ExpiredAt - cryptoTx.Signature = new(eddsa.Signature) - _, err = cryptoTx.Signature.SetBytes(txInfo.Sig) - if err != nil { - return nil, err - } - return cryptoTx, nil -} - -func toCryptoRemoveLiquidityTx(txInfo *txtypes.RemoveLiquidityTxInfo) (info *cryptoTypes.RemoveLiquidityTx, err error) { - packedAMinAmount, err := common.ToPackedAmount(txInfo.AssetAMinAmount) - if err != nil { - return nil, err - } - packedBMinAmount, err := common.ToPackedAmount(txInfo.AssetBMinAmount) - if err != nil { - return nil, err - } - packedAAmount, err := common.ToPackedAmount(txInfo.AssetAAmountDelta) - if err != nil { - return nil, err - } - packedBAmount, err := common.ToPackedAmount(txInfo.AssetBAmountDelta) - if err != nil { - return nil, err - } - packedLpAmount, err := common.ToPackedAmount(txInfo.LpAmount) - if err != nil { - return nil, err - } - packedKLast, err := common.ToPackedAmount(txInfo.KLast) - if err != nil { - return nil, err - } - packedTreasuryAmount, err := common.ToPackedAmount(txInfo.TreasuryAmount) - if err != nil { - return nil, err - } - packedFee, err := common.ToPackedFee(txInfo.GasFeeAssetAmount) - if err != nil { - return nil, err - } - info = &cryptoTypes.RemoveLiquidityTx{ - FromAccountIndex: txInfo.FromAccountIndex, - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetAId, - AssetAMinAmount: packedAMinAmount, - AssetBId: txInfo.AssetBId, - AssetBMinAmount: packedBMinAmount, - LpAmount: packedLpAmount, - KLast: packedKLast, - TreasuryAmount: packedTreasuryAmount, - AssetAAmountDelta: packedAAmount, - AssetBAmountDelta: packedBAmount, - GasAccountIndex: txInfo.GasAccountIndex, - GasFeeAssetId: txInfo.GasFeeAssetId, - GasFeeAssetAmount: packedFee, - } - return info, nil -} diff --git a/common/prove/swap.go b/common/prove/swap.go deleted file mode 100644 index 0c74675b7..000000000 --- a/common/prove/swap.go +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package prove - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254/twistededwards/eddsa" - - cryptoTypes "github.com/bnb-chain/zkbnb-crypto/circuit/types" - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - "github.com/bnb-chain/zkbnb/common" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -func (w *WitnessHelper) constructSwapTxWitness(cryptoTx *TxWitness, oTx *tx.Tx) (*TxWitness, error) { - txInfo, err := types.ParseSwapTxInfo(oTx.TxInfo) - if err != nil { - return nil, err - } - cryptoTxInfo, err := toCryptoSwapTx(txInfo) - if err != nil { - return nil, err - } - cryptoTx.SwapTxInfo = cryptoTxInfo - cryptoTx.ExpiredAt = txInfo.ExpiredAt - cryptoTx.Signature = new(eddsa.Signature) - _, err = cryptoTx.Signature.SetBytes(txInfo.Sig) - if err != nil { - return nil, err - } - return cryptoTx, nil -} - -func toCryptoSwapTx(txInfo *txtypes.SwapTxInfo) (info *cryptoTypes.SwapTx, err error) { - packedAAmount, err := common.ToPackedAmount(txInfo.AssetAAmount) - if err != nil { - return nil, err - } - packedBMinAmount, err := common.ToPackedAmount(txInfo.AssetBMinAmount) - if err != nil { - return nil, err - } - packedBAmount, err := common.ToPackedAmount(txInfo.AssetBAmountDelta) - if err != nil { - return nil, err - } - packedFee, err := common.ToPackedFee(txInfo.GasFeeAssetAmount) - if err != nil { - return nil, err - } - info = &cryptoTypes.SwapTx{ - FromAccountIndex: txInfo.FromAccountIndex, - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetAId, - AssetAAmount: packedAAmount, - AssetBId: txInfo.AssetBId, - AssetBMinAmount: packedBMinAmount, - AssetBAmountDelta: packedBAmount, - GasAccountIndex: txInfo.GasAccountIndex, - GasFeeAssetId: txInfo.GasFeeAssetId, - GasFeeAssetAmount: packedFee, - } - return info, nil -} diff --git a/common/prove/types.go b/common/prove/types.go index 67e0d16d3..5a6ed89d0 100644 --- a/common/prove/types.go +++ b/common/prove/types.go @@ -33,14 +33,12 @@ const ( NbAccountAssetsPerAccount = ctypes.NbAccountAssetsPerAccount NbAccountsPerTx = ctypes.NbAccountsPerTx - AssetMerkleLevels = circuit.AssetMerkleLevels - LiquidityMerkleLevels = circuit.LiquidityMerkleLevels - NftMerkleLevels = circuit.NftMerkleLevels - AccountMerkleLevels = circuit.AccountMerkleLevels + AssetMerkleLevels = circuit.AssetMerkleLevels + NftMerkleLevels = circuit.NftMerkleLevels + AccountMerkleLevels = circuit.AccountMerkleLevels LastAccountIndex = circuit.LastAccountIndex LastAccountAssetId = circuit.LastAccountAssetId - LastPairIndex = circuit.LastPairIndex LastNftIndex = circuit.LastNftIndex ) @@ -50,11 +48,6 @@ type AccountWitnessInfo struct { AssetsRelatedTxDetails []*tx.TxDetail } -type LiquidityWitnessInfo struct { - LiquidityInfo *types.LiquidityInfo - LiquidityRelatedTxDetail *tx.TxDetail -} - type NftWitnessInfo struct { NftInfo *types.NftInfo NftRelatedTxDetail *tx.TxDetail diff --git a/common/prove/update_pairrate.go b/common/prove/update_pairrate.go deleted file mode 100644 index ddd096e6d..000000000 --- a/common/prove/update_pairrate.go +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package prove - -import ( - cryptoTypes "github.com/bnb-chain/zkbnb-crypto/circuit/types" - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -func (w *WitnessHelper) constructUpdatePairRateTxWitness(cryptoTx *TxWitness, oTx *tx.Tx) (*TxWitness, error) { - txInfo, err := types.ParseUpdatePairRateTxInfo(oTx.TxInfo) - if err != nil { - return nil, err - } - cryptoTxInfo, err := toCryptoUpdatePairRateTx(txInfo) - if err != nil { - return nil, err - } - cryptoTx.UpdatePairRateTxInfo = cryptoTxInfo - cryptoTx.Signature = cryptoTypes.EmptySignature() - return cryptoTx, nil -} - -func toCryptoUpdatePairRateTx(txInfo *txtypes.UpdatePairRateTxInfo) (info *cryptoTypes.UpdatePairRateTx, err error) { - info = &cryptoTypes.UpdatePairRateTx{ - PairIndex: txInfo.PairIndex, - FeeRate: txInfo.FeeRate, - TreasuryAccountIndex: txInfo.TreasuryAccountIndex, - TreasuryRate: txInfo.TreasuryRate, - } - return info, nil -} diff --git a/common/prove/witness_helper.go b/common/prove/witness_helper.go index 5303db48f..d4ae44b20 100644 --- a/common/prove/witness_helper.go +++ b/common/prove/witness_helper.go @@ -39,21 +39,19 @@ type WitnessHelper struct { accountModel account.AccountModel // Trees - accountTree bsmt.SparseMerkleTree - assetTrees *tree.AssetTreeCache - liquidityTree bsmt.SparseMerkleTree - nftTree bsmt.SparseMerkleTree + accountTree bsmt.SparseMerkleTree + assetTrees *tree.AssetTreeCache + nftTree bsmt.SparseMerkleTree } -func NewWitnessHelper(treeCtx *tree.Context, accountTree, liquidityTree, nftTree bsmt.SparseMerkleTree, +func NewWitnessHelper(treeCtx *tree.Context, accountTree, nftTree bsmt.SparseMerkleTree, assetTrees *tree.AssetTreeCache, accountModel account.AccountModel) *WitnessHelper { return &WitnessHelper{ - treeCtx: treeCtx, - accountModel: accountModel, - accountTree: accountTree, - assetTrees: assetTrees, - liquidityTree: liquidityTree, - nftTree: nftTree, + treeCtx: treeCtx, + accountModel: accountModel, + accountTree: accountTree, + assetTrees: assetTrees, + nftTree: nftTree, } } @@ -72,7 +70,7 @@ func (w *WitnessHelper) ConstructTxWitness(oTx *tx.Tx, finalityBlockNr uint64, } func (w *WitnessHelper) constructTxWitness(oTx *tx.Tx, finalityBlockNr uint64) (witness *TxWitness, err error) { - if oTx == nil || w.accountTree == nil || w.assetTrees == nil || w.liquidityTree == nil || w.nftTree == nil { + if oTx == nil || w.accountTree == nil || w.assetTrees == nil || w.nftTree == nil { return nil, fmt.Errorf("failed because of nil tx or tree") } witness, err = w.constructWitnessInfo(oTx, finalityBlockNr) @@ -84,22 +82,12 @@ func (w *WitnessHelper) constructTxWitness(oTx *tx.Tx, finalityBlockNr uint64) ( switch oTx.TxType { case types.TxTypeRegisterZns: return w.constructRegisterZnsTxWitness(witness, oTx) - case types.TxTypeCreatePair: - return w.constructCreatePairTxWitness(witness, oTx) - case types.TxTypeUpdatePairRate: - return w.constructUpdatePairRateTxWitness(witness, oTx) case types.TxTypeDeposit: return w.constructDepositTxWitness(witness, oTx) case types.TxTypeDepositNft: return w.constructDepositNftTxWitness(witness, oTx) case types.TxTypeTransfer: return w.constructTransferTxWitness(witness, oTx) - case types.TxTypeSwap: - return w.constructSwapTxWitness(witness, oTx) - case types.TxTypeAddLiquidity: - return w.constructAddLiquidityTxWitness(witness, oTx) - case types.TxTypeRemoveLiquidity: - return w.constructRemoveLiquidityTxWitness(witness, oTx) case types.TxTypeWithdraw: return w.constructWithdrawTxWitness(witness, oTx) case types.TxTypeCreateCollection: @@ -130,7 +118,7 @@ func (w *WitnessHelper) constructWitnessInfo( cryptoTx *TxWitness, err error, ) { - accountKeys, proverAccounts, proverLiquidityInfo, proverNftInfo, err := w.constructSimpleWitnessInfo(oTx) + accountKeys, proverAccounts, proverNftInfo, err := w.constructSimpleWitnessInfo(oTx) if err != nil { return nil, err } @@ -140,31 +128,22 @@ func (w *WitnessHelper) constructWitnessInfo( if err != nil { return nil, err } - // construct liquidity witness - liquidityRootBefore, liquidityBefore, merkleProofsLiquidityBefore, err := - w.constructLiquidityWitness(proverLiquidityInfo) - if err != nil { - return nil, err - } // construct nft witness nftRootBefore, nftBefore, merkleProofsNftBefore, err := w.constructNftWitness(proverNftInfo) if err != nil { return nil, err } - stateRootBefore := tree.ComputeStateRootHash(accountRootBefore, liquidityRootBefore, nftRootBefore) - stateRootAfter := tree.ComputeStateRootHash(w.accountTree.Root(), w.liquidityTree.Root(), w.nftTree.Root()) + stateRootBefore := tree.ComputeStateRootHash(accountRootBefore, nftRootBefore) + stateRootAfter := tree.ComputeStateRootHash(w.accountTree.Root(), w.nftTree.Root()) cryptoTx = &TxWitness{ AccountRootBefore: accountRootBefore, AccountsInfoBefore: accountsInfoBefore, - LiquidityRootBefore: liquidityRootBefore, - LiquidityBefore: liquidityBefore, NftRootBefore: nftRootBefore, NftBefore: nftBefore, StateRootBefore: stateRootBefore, MerkleProofsAccountAssetsBefore: merkleProofsAccountAssetsBefore, MerkleProofsAccountBefore: merkleProofsAccountBefore, - MerkleProofsLiquidityBefore: merkleProofsLiquidityBefore, MerkleProofsNftBefore: merkleProofsNftBefore, StateRootAfter: stateRootAfter, } @@ -251,7 +230,6 @@ func (w *WitnessHelper) constructAccountWitness( cryptoAccount.AssetsInfo[assetCount] = &cryptoTypes.AccountAsset{ AssetId: accountAsset.AssetId, Balance: accountAsset.Balance, - LpAmount: accountAsset.LpAmount, OfferCanceledOrFinalized: accountAsset.OfferCanceledOrFinalized, } @@ -273,7 +251,7 @@ func (w *WitnessHelper) constructAccountWitness( if err != nil { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err } - nAssetHash, err := tree.ComputeAccountAssetLeafHash(nAsset.Balance.String(), nAsset.LpAmount.String(), nAsset.OfferCanceledOrFinalized.String()) + nAssetHash, err := tree.ComputeAccountAssetLeafHash(nAsset.Balance.String(), nAsset.OfferCanceledOrFinalized.String()) if err != nil { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err } @@ -370,84 +348,6 @@ func (w *WitnessHelper) constructAccountWitness( return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, nil } -func (w *WitnessHelper) constructLiquidityWitness( - proverLiquidityInfo *LiquidityWitnessInfo, -) ( - // liquidity root before - LiquidityRootBefore []byte, - // liquidity before - LiquidityBefore *cryptoTypes.Liquidity, - // before liquidity merkle proof - MerkleProofsLiquidityBefore [LiquidityMerkleLevels][]byte, - err error, -) { - LiquidityRootBefore = w.liquidityTree.Root() - if proverLiquidityInfo == nil { - liquidityMerkleProofs, err := w.liquidityTree.GetProof(LastPairIndex) - if err != nil { - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, err - } - MerkleProofsLiquidityBefore, err = SetFixedLiquidityArray(liquidityMerkleProofs) - if err != nil { - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, err - } - LiquidityBefore = cryptoTypes.EmptyLiquidity(LastPairIndex) - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, nil - } - liquidityMerkleProofs, err := w.liquidityTree.GetProof(uint64(proverLiquidityInfo.LiquidityInfo.PairIndex)) - if err != nil { - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, err - } - MerkleProofsLiquidityBefore, err = SetFixedLiquidityArray(liquidityMerkleProofs) - if err != nil { - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, err - } - LiquidityBefore = &cryptoTypes.Liquidity{ - PairIndex: proverLiquidityInfo.LiquidityInfo.PairIndex, - AssetAId: proverLiquidityInfo.LiquidityInfo.AssetAId, - AssetA: proverLiquidityInfo.LiquidityInfo.AssetA, - AssetBId: proverLiquidityInfo.LiquidityInfo.AssetBId, - AssetB: proverLiquidityInfo.LiquidityInfo.AssetB, - LpAmount: proverLiquidityInfo.LiquidityInfo.LpAmount, - KLast: proverLiquidityInfo.LiquidityInfo.KLast, - FeeRate: proverLiquidityInfo.LiquidityInfo.FeeRate, - TreasuryAccountIndex: proverLiquidityInfo.LiquidityInfo.TreasuryAccountIndex, - TreasuryRate: proverLiquidityInfo.LiquidityInfo.TreasuryRate, - } - // update liquidity tree - nBalance, err := chain.ComputeNewBalance( - proverLiquidityInfo.LiquidityRelatedTxDetail.AssetType, - proverLiquidityInfo.LiquidityRelatedTxDetail.Balance, - proverLiquidityInfo.LiquidityRelatedTxDetail.BalanceDelta, - ) - if err != nil { - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, err - } - nPoolInfo, err := types.ParseLiquidityInfo(nBalance) - if err != nil { - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, err - } - nLiquidityHash, err := tree.ComputeLiquidityAssetLeafHash( - nPoolInfo.AssetAId, - nPoolInfo.AssetA.String(), - nPoolInfo.AssetBId, - nPoolInfo.AssetB.String(), - nPoolInfo.LpAmount.String(), - nPoolInfo.KLast.String(), - nPoolInfo.FeeRate, - nPoolInfo.TreasuryAccountIndex, - nPoolInfo.TreasuryRate, - ) - if err != nil { - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, err - } - err = w.liquidityTree.Set(uint64(proverLiquidityInfo.LiquidityInfo.PairIndex), nLiquidityHash) - if err != nil { - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, err - } - return LiquidityRootBefore, LiquidityBefore, MerkleProofsLiquidityBefore, nil -} - func (w *WitnessHelper) constructNftWitness( proverNftInfo *NftWitnessInfo, ) ( @@ -461,11 +361,11 @@ func (w *WitnessHelper) constructNftWitness( ) { nftRootBefore = w.nftTree.Root() if proverNftInfo == nil { - liquidityMerkleProofs, err := w.nftTree.GetProof(LastNftIndex) + nftMerkleProofs, err := w.nftTree.GetProof(LastNftIndex) if err != nil { return nftRootBefore, nftBefore, merkleProofsNftBefore, err } - merkleProofsNftBefore, err = SetFixedNftArray(liquidityMerkleProofs) + merkleProofsNftBefore, err = SetFixedNftArray(nftMerkleProofs) if err != nil { return nftRootBefore, nftBefore, merkleProofsNftBefore, err } @@ -494,7 +394,7 @@ func (w *WitnessHelper) constructNftWitness( CreatorTreasuryRate: proverNftInfo.NftInfo.CreatorTreasuryRate, CollectionId: proverNftInfo.NftInfo.CollectionId, } - // update liquidity tree + nBalance, err := chain.ComputeNewBalance( proverNftInfo.NftRelatedTxDetail.AssetType, proverNftInfo.NftRelatedTxDetail.Balance, @@ -546,14 +446,6 @@ func SetFixedAccountAssetArray(proof [][]byte) (res [AssetMerkleLevels][]byte, e return res, nil } -func SetFixedLiquidityArray(proof [][]byte) (res [LiquidityMerkleLevels][]byte, err error) { - if len(proof) != LiquidityMerkleLevels { - return res, fmt.Errorf("invalid size") - } - copy(res[:], proof[:]) - return res, nil -} - func SetFixedNftArray(proof [][]byte) (res [NftMerkleLevels][]byte, err error) { if len(proof) != NftMerkleLevels { return res, fmt.Errorf("invalid size") @@ -565,7 +457,6 @@ func SetFixedNftArray(proof [][]byte) (res [NftMerkleLevels][]byte, err error) { func (w *WitnessHelper) constructSimpleWitnessInfo(oTx *tx.Tx) ( accountKeys []int64, accountWitnessInfo []*AccountWitnessInfo, - liquidityWitnessInfo *LiquidityWitnessInfo, nftWitnessInfo *NftWitnessInfo, err error, ) { @@ -587,7 +478,7 @@ func (w *WitnessHelper) constructSimpleWitnessInfo(oTx *tx.Tx) ( if accountMap[txDetail.AccountIndex] == nil { accountInfo, err := w.accountModel.GetConfirmedAccountByIndex(txDetail.AccountIndex) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, err } // get current nonce accountInfo.Nonce = txDetail.Nonce @@ -625,7 +516,7 @@ func (w *WitnessHelper) constructSimpleWitnessInfo(oTx *tx.Tx) ( // set account before info oAsset, err := types.ParseAccountAsset(txDetail.Balance) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, err } accountWitnessInfo[accountCount].AccountAssets = append( accountWitnessInfo[accountCount].AccountAssets, @@ -638,7 +529,6 @@ func (w *WitnessHelper) constructSimpleWitnessInfo(oTx *tx.Tx) ( &types.AccountAsset{ AssetId: accountAssetMap[txDetail.AccountIndex][txDetail.AssetId].AssetId, Balance: accountAssetMap[txDetail.AccountIndex][txDetail.AssetId].Balance, - LpAmount: accountAssetMap[txDetail.AccountIndex][txDetail.AssetId].LpAmount, OfferCanceledOrFinalized: accountAssetMap[txDetail.AccountIndex][txDetail.AssetId].OfferCanceledOrFinalized, }, ) @@ -651,27 +541,19 @@ func (w *WitnessHelper) constructSimpleWitnessInfo(oTx *tx.Tx) ( // update asset info newBalance, err := chain.ComputeNewBalance(txDetail.AssetType, txDetail.Balance, txDetail.BalanceDelta) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, err } nAsset, err := types.ParseAccountAsset(newBalance) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, err } accountAssetMap[txDetail.AccountIndex][txDetail.AssetId] = nAsset - case types.LiquidityAssetType: - liquidityWitnessInfo = new(LiquidityWitnessInfo) - liquidityWitnessInfo.LiquidityRelatedTxDetail = txDetail - poolInfo, err := types.ParseLiquidityInfo(txDetail.Balance) - if err != nil { - return nil, nil, nil, nil, err - } - liquidityWitnessInfo.LiquidityInfo = poolInfo case types.NftAssetType: nftWitnessInfo = new(NftWitnessInfo) nftWitnessInfo.NftRelatedTxDetail = txDetail nftInfo, err := types.ParseNftInfo(txDetail.Balance) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, err } nftWitnessInfo.NftInfo = nftInfo case types.CollectionNonceAssetType: @@ -679,7 +561,7 @@ func (w *WitnessHelper) constructSimpleWitnessInfo(oTx *tx.Tx) ( if accountMap[txDetail.AccountIndex] == nil { accountInfo, err := w.accountModel.GetConfirmedAccountByIndex(txDetail.AccountIndex) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, err } // get current nonce accountInfo.Nonce = txDetail.Nonce @@ -709,9 +591,9 @@ func (w *WitnessHelper) constructSimpleWitnessInfo(oTx *tx.Tx) ( accountMap[txDetail.AccountIndex].CollectionNonce = txDetail.CollectionNonce } default: - return nil, nil, nil, nil, + return nil, nil, nil, fmt.Errorf("invalid asset type") } } - return accountKeys, accountWitnessInfo, liquidityWitnessInfo, nftWitnessInfo, nil + return accountKeys, accountWitnessInfo, nftWitnessInfo, nil } diff --git a/common/prove/witness_test.go b/common/prove/witness_test.go index b52d2c88c..02ba66463 100644 --- a/common/prove/witness_test.go +++ b/common/prove/witness_test.go @@ -33,20 +33,18 @@ import ( "github.com/bnb-chain/zkbnb/dao/account" "github.com/bnb-chain/zkbnb/dao/block" "github.com/bnb-chain/zkbnb/dao/blockwitness" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/tree" ) var ( - dsn = "host=localhost user=postgres password=ZkBNB@123 dbname=zkbnb port=5434 sslmode=disable" - blockModel block.BlockModel - witnessModel blockwitness.BlockWitnessModel - accountModel account.AccountModel - accountHistoryModel account.AccountHistoryModel - liquidityHistoryModel liquidity.LiquidityHistoryModel - nftHistoryModel nft.L2NftHistoryModel - assetTreeCacheSize = 512000 + dsn = "host=localhost user=postgres password=ZkBNB@123 dbname=zkbnb port=5434 sslmode=disable" + blockModel block.BlockModel + witnessModel blockwitness.BlockWitnessModel + accountModel account.AccountModel + accountHistoryModel account.AccountHistoryModel + nftHistoryModel nft.L2NftHistoryModel + assetTreeCacheSize = 512000 ) func TestConstructTxWitness(t *testing.T) { @@ -82,17 +80,12 @@ func getWitnessHelper(blockHeight int64) (*WitnessHelper, error) { if err != nil { return nil, err } - liquidityTree, err := tree.InitLiquidityTree(liquidityHistoryModel, blockHeight, ctx) - if err != nil { - return nil, err - } nftTree, err := tree.InitNftTree(nftHistoryModel, blockHeight, ctx) if err != nil { return nil, err } return NewWitnessHelper(ctx, accountTree, - liquidityTree, nftTree, accountAssetTrees, accountModel), nil @@ -103,7 +96,7 @@ func testDBSetup() { time.Sleep(5 * time.Second) cmd := exec.Command("docker", "run", "--name", "postgres-ut-witness", "-p", "5434:5432", "-e", "POSTGRES_PASSWORD=ZkBNB@123", "-e", "POSTGRES_USER=postgres", "-e", "POSTGRES_DB=zkbnb", - "-e", "PGDATA=/var/lib/postgresql/pgdata", "-d", "ghcr.io/bnb-chain/zkbnb/zkbnb-ut-postgres:0.0.2") + "-e", "PGDATA=/var/lib/postgresql/pgdata", "-d", "ghcr.io/bnb-chain/zkbnb/zkbnb-ut-postgres:igor") if err := cmd.Run(); err != nil { panic(err) } @@ -113,7 +106,6 @@ func testDBSetup() { witnessModel = blockwitness.NewBlockWitnessModel(db) accountModel = account.NewAccountModel(db) accountHistoryModel = account.NewAccountHistoryModel(db) - liquidityHistoryModel = liquidity.NewLiquidityHistoryModel(db) nftHistoryModel = nft.NewL2NftHistoryModel(db) } diff --git a/core/blockchain.go b/core/blockchain.go index e6d2083db..7416ed80e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -22,7 +22,6 @@ import ( "github.com/bnb-chain/zkbnb/dao/block" "github.com/bnb-chain/zkbnb/dao/compressedblock" "github.com/bnb-chain/zkbnb/dao/dbcache" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/dao/sysconfig" "github.com/bnb-chain/zkbnb/dao/tx" @@ -110,12 +109,11 @@ func NewBlockChain(config *ChainConfig, moduleName string) (*BlockChain, error) // NewBlockChainForDryRun - for dry run mode, we can reuse existing models for quick creation // , e.g., for sending tx, we can create blockchain for each request quickly -func NewBlockChainForDryRun(accountModel account.AccountModel, liquidityModel liquidity.LiquidityModel, +func NewBlockChainForDryRun(accountModel account.AccountModel, nftModel nft.L2NftModel, txPoolModel tx.TxPoolModel, assetModel asset.AssetModel, sysConfigModel sysconfig.SysConfigModel, redisCache dbcache.Cache) (*BlockChain, error) { chainDb := &sdb.ChainDB{ AccountModel: accountModel, - LiquidityModel: liquidityModel, L2NftModel: nftModel, TxPoolModel: txPoolModel, L2AssetInfoModel: assetModel, @@ -165,17 +163,13 @@ func (bc *BlockChain) CommitNewBlock(blockSize int, createdAt int64) (*block.Blo } currentHeight := bc.currentBlock.BlockHeight - err = tree.CommitTrees(bc.taskPool, uint64(currentHeight), bc.Statedb.AccountTree, bc.Statedb.AccountAssetTrees, bc.Statedb.LiquidityTree, bc.Statedb.NftTree) - if err != nil { - return nil, err - } - pendingNewAccount, pendingUpdateAccount, pendingNewAccountHistory, err := bc.Statedb.GetPendingAccount(currentHeight) + err = tree.CommitTrees(bc.taskPool, uint64(currentHeight), bc.Statedb.AccountTree, bc.Statedb.AccountAssetTrees, bc.Statedb.NftTree) if err != nil { return nil, err } - pendingNewLiquidity, pendingUpdateLiquidity, pendingNewLiquidityHistory, err := bc.Statedb.GetPendingLiquidity(currentHeight) + pendingNewAccount, pendingUpdateAccount, pendingNewAccountHistory, err := bc.Statedb.GetPendingAccount(currentHeight) if err != nil { return nil, err } @@ -186,17 +180,14 @@ func (bc *BlockChain) CommitNewBlock(blockSize int, createdAt int64) (*block.Blo } return &block.BlockStates{ - Block: newBlock, - CompressedBlock: compressedBlock, - PendingNewAccount: pendingNewAccount, - PendingUpdateAccount: pendingUpdateAccount, - PendingNewAccountHistory: pendingNewAccountHistory, - PendingNewLiquidity: pendingNewLiquidity, - PendingUpdateLiquidity: pendingUpdateLiquidity, - PendingNewLiquidityHistory: pendingNewLiquidityHistory, - PendingNewNft: pendingNewNft, - PendingUpdateNft: pendingUpdateNft, - PendingNewNftHistory: pendingNewNftHistory, + Block: newBlock, + CompressedBlock: compressedBlock, + PendingNewAccount: pendingNewAccount, + PendingUpdateAccount: pendingUpdateAccount, + PendingNewAccountHistory: pendingNewAccountHistory, + PendingNewNft: pendingNewNft, + PendingUpdateNft: pendingUpdateNft, + PendingNewNftHistory: pendingNewNftHistory, }, nil } diff --git a/core/executor/add_liquidity_executor.go b/core/executor/add_liquidity_executor.go deleted file mode 100644 index abed5e953..000000000 --- a/core/executor/add_liquidity_executor.go +++ /dev/null @@ -1,549 +0,0 @@ -package executor - -import ( - "bytes" - "encoding/json" - "math/big" - - "github.com/pkg/errors" - "github.com/zeromicro/go-zero/core/logx" - - "github.com/bnb-chain/zkbnb-crypto/ffmath" - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - common2 "github.com/bnb-chain/zkbnb/common" - "github.com/bnb-chain/zkbnb/common/chain" - "github.com/bnb-chain/zkbnb/dao/liquidity" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -type AddLiquidityExecutor struct { - BaseExecutor - - txInfo *txtypes.AddLiquidityTxInfo - - newPoolInfo *types.LiquidityInfo - lpDeltaForFromAccount *big.Int -} - -func NewAddLiquidityExecutor(bc IBlockchain, tx *tx.Tx) (TxExecutor, error) { - txInfo, err := types.ParseAddLiquidityTxInfo(tx.TxInfo) - if err != nil { - logx.Errorf("parse transfer tx failed: %s", err.Error()) - return nil, errors.New("invalid tx info") - } - - return &AddLiquidityExecutor{ - BaseExecutor: NewBaseExecutor(bc, tx, txInfo), - txInfo: txInfo, - }, nil -} - -func (e *AddLiquidityExecutor) Prepare() error { - txInfo := e.txInfo - - err := e.bc.StateDB().PrepareLiquidity(txInfo.PairIndex) - if err != nil { - logx.Errorf("prepare liquidity failed: %s", err.Error()) - return errors.New("internal error") - } - - // Add the right details to tx info. - err = e.fillTxInfo() - if err != nil { - return err - } - - // Mark the tree states that would be affected in this executor. - e.MarkLiquidityDirty(txInfo.PairIndex) - e.MarkAccountAssetsDirty(txInfo.FromAccountIndex, []int64{txInfo.GasFeeAssetId, txInfo.AssetAId, txInfo.AssetBId, txInfo.PairIndex}) - liquidity, err := e.bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - e.MarkAccountAssetsDirty(liquidity.TreasuryAccountIndex, []int64{txInfo.PairIndex}) - e.MarkAccountAssetsDirty(txInfo.GasAccountIndex, []int64{txInfo.GasFeeAssetId}) - err = e.BaseExecutor.Prepare() - if err != nil { - return err - } - - return nil -} - -func (e *AddLiquidityExecutor) VerifyInputs(skipGasAmtChk bool) error { - bc := e.bc - txInfo := e.txInfo - - err := e.BaseExecutor.VerifyInputs(skipGasAmtChk) - if err != nil { - return err - } - - fromAccount, err := bc.StateDB().GetFormatAccount(txInfo.FromAccountIndex) - if err != nil { - return err - } - if txInfo.GasFeeAssetId == txInfo.AssetAId { - deltaBalance := ffmath.Add(txInfo.AssetAAmount, txInfo.GasFeeAssetAmount) - if fromAccount.AssetInfo[txInfo.AssetAId].Balance.Cmp(deltaBalance) < 0 { - return errors.New("invalid asset amount") - } - if fromAccount.AssetInfo[txInfo.AssetBId].Balance.Cmp(txInfo.AssetBAmount) < 0 { - return errors.New("invalid asset amount") - } - } else if txInfo.GasFeeAssetId == txInfo.AssetBId { - deltaBalance := ffmath.Add(txInfo.AssetBAmount, txInfo.GasFeeAssetAmount) - if fromAccount.AssetInfo[txInfo.AssetBId].Balance.Cmp(deltaBalance) < 0 { - return errors.New("invalid asset amount") - } - if fromAccount.AssetInfo[txInfo.AssetAId].Balance.Cmp(txInfo.AssetAAmount) < 0 { - return errors.New("invalid asset amount") - } - } else { - if fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance.Cmp(txInfo.GasFeeAssetAmount) < 0 { - return errors.New("invalid gas asset amount") - } - if fromAccount.AssetInfo[txInfo.AssetAId].Balance.Cmp(txInfo.AssetAAmount) < 0 { - return errors.New("invalid asset amount") - } - if fromAccount.AssetInfo[txInfo.AssetBId].Balance.Cmp(txInfo.AssetBAmount) < 0 { - return errors.New("invalid asset amount") - } - } - - liquidityModel, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - liquidityInfo, err := constructLiquidityInfo(liquidityModel) - if err != nil { - logx.Errorf("construct liquidity info error, err: %v", err) - return err - } - - if liquidityInfo.AssetA == nil || liquidityInfo.AssetB == nil { - return errors.New("invalid liquidity") - } - - return nil -} - -func (e *AddLiquidityExecutor) ApplyTransaction() error { - bc := e.bc - txInfo := e.txInfo - - // apply changes - fromAccount, err := bc.StateDB().GetFormatAccount(txInfo.FromAccountIndex) - if err != nil { - return err - } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } - liquidityModel, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - treasuryAccount, err := bc.StateDB().GetFormatAccount(liquidityModel.TreasuryAccountIndex) - if err != nil { - return err - } - - fromAccount.AssetInfo[txInfo.AssetAId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.AssetAId].Balance, txInfo.AssetAAmount) - fromAccount.AssetInfo[txInfo.AssetBId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.AssetBId].Balance, txInfo.AssetBAmount) - fromAccount.AssetInfo[txInfo.PairIndex].LpAmount = ffmath.Add(fromAccount.AssetInfo[txInfo.PairIndex].LpAmount, e.lpDeltaForFromAccount) - treasuryAccount.AssetInfo[txInfo.PairIndex].LpAmount = ffmath.Add(treasuryAccount.AssetInfo[txInfo.PairIndex].LpAmount, txInfo.TreasuryAmount) - fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - fromAccount.Nonce++ - - stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(fromAccount.AccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(treasuryAccount.AccountIndex, treasuryAccount) - stateCache.SetPendingUpdateAccount(gasAccount.AccountIndex, gasAccount) - stateCache.SetPendingUpdateLiquidity(txInfo.PairIndex, &liquidity.Liquidity{ - Model: liquidityModel.Model, - PairIndex: e.newPoolInfo.PairIndex, - AssetAId: liquidityModel.AssetAId, - AssetA: e.newPoolInfo.AssetA.String(), - AssetBId: liquidityModel.AssetBId, - AssetB: e.newPoolInfo.AssetB.String(), - LpAmount: e.newPoolInfo.LpAmount.String(), - KLast: e.newPoolInfo.KLast.String(), - FeeRate: e.newPoolInfo.FeeRate, - TreasuryAccountIndex: e.newPoolInfo.TreasuryAccountIndex, - TreasuryRate: e.newPoolInfo.TreasuryRate, - }) - return e.BaseExecutor.ApplyTransaction() -} - -func (e *AddLiquidityExecutor) fillTxInfo() error { - bc := e.bc - txInfo := e.txInfo - - liquidityModel, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - - liquidityInfo, err := constructLiquidityInfo(liquidityModel) - if err != nil { - logx.Errorf("construct liquidity info error, err: %v", err) - return err - } - - if liquidityInfo.AssetA.Cmp(types.ZeroBigInt) == 0 { - txInfo.LpAmount, err = chain.ComputeEmptyLpAmount(txInfo.AssetAAmount, txInfo.AssetBAmount) - if err != nil { - logx.Errorf("[ComputeEmptyLpAmount] : %v", err) - return err - } - } else { - txInfo.LpAmount, err = chain.ComputeLpAmount(liquidityInfo, txInfo.AssetAAmount) - if err != nil { - return err - } - } - - txInfo.AssetAId = liquidityInfo.AssetAId - txInfo.AssetBId = liquidityInfo.AssetBId - - lpDeltaForTreasuryAccount, err := chain.ComputeSLp(liquidityInfo.AssetA, - liquidityInfo.AssetB, liquidityInfo.KLast, liquidityInfo.FeeRate, liquidityInfo.TreasuryRate) - if err != nil { - logx.Errorf("[ComputeSLp] err: %v", err) - return err - } - - // pool account pool info - finalPoolA := ffmath.Add(liquidityInfo.AssetA, txInfo.AssetAAmount) - finalPoolB := ffmath.Add(liquidityInfo.AssetB, txInfo.AssetBAmount) - - txInfo.TreasuryAmount = lpDeltaForTreasuryAccount - txInfo.KLast, err = common2.CleanPackedAmount(ffmath.Multiply(finalPoolA, finalPoolB)) - if err != nil { - return err - } - - txInfo.AssetAId = liquidityModel.AssetAId - txInfo.AssetBId = liquidityModel.AssetBId - - return nil -} - -func (e *AddLiquidityExecutor) GeneratePubData() error { - txInfo := e.txInfo - - var buf bytes.Buffer - buf.WriteByte(uint8(types.TxTypeAddLiquidity)) - buf.Write(common2.Uint32ToBytes(uint32(txInfo.FromAccountIndex))) - buf.Write(common2.Uint16ToBytes(uint16(txInfo.PairIndex))) - packedAssetAAmountBytes, err := common2.AmountToPackedAmountBytes(txInfo.AssetAAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(packedAssetAAmountBytes) - packedAssetBAmountBytes, err := common2.AmountToPackedAmountBytes(txInfo.AssetBAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(packedAssetBAmountBytes) - LpAmountBytes, err := common2.AmountToPackedAmountBytes(txInfo.LpAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(LpAmountBytes) - KLastBytes, err := common2.AmountToPackedAmountBytes(txInfo.KLast) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(KLastBytes) - chunk1 := common2.SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - treasuryAmountBytes, err := common2.AmountToPackedAmountBytes(txInfo.TreasuryAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(treasuryAmountBytes) - buf.Write(common2.Uint32ToBytes(uint32(txInfo.GasAccountIndex))) - buf.Write(common2.Uint16ToBytes(uint16(txInfo.GasFeeAssetId))) - packedFeeBytes, err := common2.FeeToPackedFeeBytes(txInfo.GasFeeAssetAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed fee amount: %s", err.Error()) - return err - } - buf.Write(packedFeeBytes) - chunk2 := common2.PrefixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk1) - buf.Write(chunk2) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - pubData := buf.Bytes() - - stateCache := e.bc.StateDB() - stateCache.PubData = append(stateCache.PubData, pubData...) - return nil -} - -func (e *AddLiquidityExecutor) GetExecutedTx() (*tx.Tx, error) { - txInfoBytes, err := json.Marshal(e.txInfo) - if err != nil { - logx.Errorf("unable to marshal tx, err: %s", err.Error()) - return nil, errors.New("unmarshal tx failed") - } - - e.tx.TxInfo = string(txInfoBytes) - e.tx.GasFeeAssetId = e.txInfo.GasFeeAssetId - e.tx.GasFee = e.txInfo.GasFeeAssetAmount.String() - e.tx.PairIndex = e.txInfo.PairIndex - e.tx.TxAmount = e.txInfo.LpAmount.String() - return e.BaseExecutor.GetExecutedTx() -} - -func (e *AddLiquidityExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { - txInfo := e.txInfo - - liquidityModel, err := e.bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return nil, err - } - liquidityInfo, err := constructLiquidityInfo(liquidityModel) - if err != nil { - logx.Errorf("construct liquidity info error, err: %v", err) - return nil, err - } - - copiedAccounts, err := e.bc.StateDB().DeepCopyAccounts([]int64{txInfo.FromAccountIndex, txInfo.GasAccountIndex, liquidityInfo.TreasuryAccountIndex}) - if err != nil { - return nil, err - } - - fromAccount := copiedAccounts[txInfo.FromAccountIndex] - gasAccount := copiedAccounts[txInfo.GasAccountIndex] - treasuryAccount := copiedAccounts[liquidityInfo.TreasuryAccountIndex] - - txDetails := make([]*tx.TxDetail, 0, 4) - // from account asset A - order := int64(0) - accountOrder := int64(0) - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.AssetAId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.AssetAId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.AssetAId, - ffmath.Neg(txInfo.AssetAAmount), - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - fromAccount.AssetInfo[txInfo.AssetAId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.AssetAId].Balance, txInfo.AssetAAmount) - if fromAccount.AssetInfo[txInfo.AssetAId].Balance.Cmp(types.ZeroBigInt) < 0 { - return nil, errors.New("insufficient asset a balance") - } - - // from account asset B - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.AssetBId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.AssetBId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.AssetBId, - ffmath.Neg(txInfo.AssetBAmount), - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - - fromAccount.AssetInfo[txInfo.AssetBId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.AssetBId].Balance, txInfo.AssetBAmount) - if fromAccount.AssetInfo[txInfo.AssetBId].Balance.Cmp(types.ZeroBigInt) < 0 { - return nil, errors.New("insufficient asset b balance") - } - - // from account asset gas - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.GasFeeAssetId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.GasFeeAssetId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, - ffmath.Neg(txInfo.GasFeeAssetAmount), - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - - fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - if fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance.Cmp(types.ZeroBigInt) < 0 { - return nil, errors.New("insufficient gas fee balance") - } - - // from account lp - poolLp := ffmath.Sub(liquidityInfo.LpAmount, txInfo.TreasuryAmount) - var lpDeltaForFromAccount *big.Int - if liquidityInfo.AssetA.Cmp(types.ZeroBigInt) == 0 { - lpDeltaForFromAccount, err = common2.CleanPackedAmount(new(big.Int).Sqrt(ffmath.Multiply(txInfo.AssetAAmount, txInfo.AssetBAmount))) - if err != nil { - logx.Errorf("unable to compute lp delta: %s", err.Error()) - return nil, err - } - } else { - lpDeltaForFromAccount, err = common2.CleanPackedAmount(ffmath.Div(ffmath.Multiply(txInfo.AssetAAmount, poolLp), liquidityInfo.AssetA)) - if err != nil { - logx.Errorf(" unable to compute lp delta: %s", err.Error()) - return nil, err - } - } - - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.PairIndex, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.PairIndex].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.PairIndex, - types.ZeroBigInt, - lpDeltaForFromAccount, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - e.lpDeltaForFromAccount = lpDeltaForFromAccount - fromAccount.AssetInfo[txInfo.PairIndex].LpAmount = ffmath.Add(fromAccount.AssetInfo[txInfo.PairIndex].LpAmount, lpDeltaForFromAccount) - - // pool info - liquidity, err := e.bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return nil, err - } - basePool, err := types.ConstructLiquidityInfo( - liquidity.PairIndex, - liquidity.AssetAId, - liquidity.AssetA, - liquidity.AssetBId, - liquidity.AssetB, - liquidity.LpAmount, - liquidity.KLast, - liquidity.FeeRate, - liquidity.TreasuryAccountIndex, - liquidity.TreasuryRate, - ) - if err != nil { - return nil, err - } - - finalPoolA := ffmath.Add(liquidityInfo.AssetA, txInfo.AssetAAmount) - finalPoolB := ffmath.Add(liquidityInfo.AssetB, txInfo.AssetBAmount) - poolDeltaForToAccount := &types.LiquidityInfo{ - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetAId, - AssetA: txInfo.AssetAAmount, - AssetBId: txInfo.AssetBId, - AssetB: txInfo.AssetAAmount, - LpAmount: lpDeltaForFromAccount, - KLast: ffmath.Multiply(finalPoolA, finalPoolB), - FeeRate: liquidityInfo.FeeRate, - TreasuryAccountIndex: liquidityInfo.TreasuryAccountIndex, - TreasuryRate: liquidityInfo.TreasuryRate, - } - newPool, err := chain.ComputeNewBalance(types.LiquidityAssetType, basePool.String(), poolDeltaForToAccount.String()) - if err != nil { - return nil, err - } - - newPoolInfo, err := types.ParseLiquidityInfo(newPool) - if err != nil { - return nil, err - } - e.newPoolInfo = newPoolInfo - - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.PairIndex, - AssetType: types.LiquidityAssetType, - AccountIndex: types.NilAccountIndex, - AccountName: types.NilAccountName, - Balance: basePool.String(), - BalanceDelta: poolDeltaForToAccount.String(), - Order: order, - Nonce: 0, - AccountOrder: types.NilAccountOrder, - CollectionNonce: 0, - }) - - // treasury account - order++ - accountOrder++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.PairIndex, - AssetType: types.FungibleAssetType, - AccountIndex: treasuryAccount.AccountIndex, - AccountName: treasuryAccount.AccountName, - Balance: treasuryAccount.AssetInfo[txInfo.PairIndex].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.PairIndex, types.ZeroBigInt, txInfo.TreasuryAmount, types.ZeroBigInt, - ).String(), - Order: order, - Nonce: treasuryAccount.Nonce, - AccountOrder: accountOrder, - CollectionNonce: treasuryAccount.CollectionNonce, - }) - treasuryAccount.AssetInfo[txInfo.PairIndex].LpAmount = ffmath.Add(treasuryAccount.AssetInfo[txInfo.PairIndex].LpAmount, txInfo.TreasuryAmount) - - // gas account asset gas - order++ - accountOrder++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.GasFeeAssetId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.GasAccountIndex, - AccountName: gasAccount.AccountName, - Balance: gasAccount.AssetInfo[txInfo.GasFeeAssetId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, - txInfo.GasFeeAssetAmount, - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: gasAccount.Nonce, - CollectionNonce: gasAccount.CollectionNonce, - }) - return txDetails, nil -} diff --git a/core/executor/atomic_match_executor.go b/core/executor/atomic_match_executor.go index 4d08fa446..ec27d92d6 100644 --- a/core/executor/atomic_match_executor.go +++ b/core/executor/atomic_match_executor.go @@ -321,7 +321,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: fromAccount.AccountName, Balance: fromAccount.AssetInfo[txInfo.GasFeeAssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: fromAccount.Nonce, @@ -339,7 +339,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: buyAccount.AccountName, Balance: buyAccount.AssetInfo[txInfo.BuyOffer.AssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.BuyOffer.AssetId, ffmath.Neg(txInfo.BuyOffer.AssetAmount), types.ZeroBigInt, types.ZeroBigInt, + txInfo.BuyOffer.AssetId, ffmath.Neg(txInfo.BuyOffer.AssetAmount), types.ZeroBigInt, ).String(), Order: order, AccountOrder: accountOrder, @@ -359,7 +359,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: buyAccount.AccountName, Balance: buyAccount.AssetInfo[e.buyOfferAssetId].String(), BalanceDelta: types.ConstructAccountAsset( - e.buyOfferAssetId, types.ZeroBigInt, types.ZeroBigInt, buyOffer).String(), + e.buyOfferAssetId, types.ZeroBigInt, buyOffer).String(), Order: order, AccountOrder: accountOrder, Nonce: buyAccount.Nonce, @@ -378,7 +378,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: sellAccount.AccountName, Balance: sellAccount.AssetInfo[txInfo.SellOffer.AssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.SellOffer.AssetId, sellDeltaAmount, types.ZeroBigInt, types.ZeroBigInt, + txInfo.SellOffer.AssetId, sellDeltaAmount, types.ZeroBigInt, ).String(), Order: order, AccountOrder: accountOrder, @@ -398,7 +398,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: sellAccount.AccountName, Balance: sellAccount.AssetInfo[e.sellOfferAssetId].String(), BalanceDelta: types.ConstructAccountAsset( - e.sellOfferAssetId, types.ZeroBigInt, types.ZeroBigInt, sellOffer).String(), + e.sellOfferAssetId, types.ZeroBigInt, sellOffer).String(), Order: order, AccountOrder: accountOrder, Nonce: sellAccount.Nonce, @@ -416,7 +416,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: creatorAccount.AccountName, Balance: creatorAccount.AssetInfo[txInfo.BuyOffer.AssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.BuyOffer.AssetId, txInfo.CreatorAmount, types.ZeroBigInt, types.ZeroBigInt, + txInfo.BuyOffer.AssetId, txInfo.CreatorAmount, types.ZeroBigInt, ).String(), Order: order, AccountOrder: accountOrder, @@ -452,7 +452,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: gasAccount.AccountName, Balance: gasAccount.AssetInfo[txInfo.BuyOffer.AssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.BuyOffer.AssetId, txInfo.TreasuryAmount, types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.BuyOffer.AssetId, txInfo.TreasuryAmount, types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: gasAccount.Nonce, @@ -469,7 +469,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: gasAccount.AccountName, Balance: gasAccount.AssetInfo[txInfo.GasFeeAssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: gasAccount.Nonce, diff --git a/core/executor/base_executor.go b/core/executor/base_executor.go index f14889641..a38fb7cf8 100644 --- a/core/executor/base_executor.go +++ b/core/executor/base_executor.go @@ -23,7 +23,6 @@ type BaseExecutor struct { // Affected states. dirtyAccountsAndAssetsMap map[int64]map[int64]bool - dirtyLiquidityMap map[int64]bool dirtyNftMap map[int64]bool } @@ -34,7 +33,6 @@ func NewBaseExecutor(bc IBlockchain, tx *tx.Tx, txInfo txtypes.TxInfo) BaseExecu iTxInfo: txInfo, dirtyAccountsAndAssetsMap: make(map[int64]map[int64]bool, 0), - dirtyLiquidityMap: make(map[int64]bool, 0), dirtyNftMap: make(map[int64]bool, 0), } } @@ -139,10 +137,6 @@ func (e *BaseExecutor) MarkAccountAssetsDirty(accountIndex int64, assets []int64 } } -func (e *BaseExecutor) MarkLiquidityDirty(pairIndex int64) { - e.dirtyLiquidityMap[pairIndex] = true -} - func (e *BaseExecutor) MarkNftDirty(nftIndex int64) { e.dirtyNftMap[nftIndex] = true } @@ -156,10 +150,6 @@ func (e *BaseExecutor) SyncDirtyToStateCache() { e.bc.StateDB().MarkAccountAssetsDirty(accountIndex, assets) } - for pairIndex := range e.dirtyLiquidityMap { - e.bc.StateDB().MarkLiquidityDirty(pairIndex) - } - for nftIndex := range e.dirtyNftMap { e.bc.StateDB().MarkNftDirty(nftIndex) } diff --git a/core/executor/cancel_offer_executor.go b/core/executor/cancel_offer_executor.go index 04566697e..66fd7f7a6 100644 --- a/core/executor/cancel_offer_executor.go +++ b/core/executor/cancel_offer_executor.go @@ -171,7 +171,6 @@ func (e *CancelOfferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: fromAccount.Nonce, @@ -204,7 +203,6 @@ func (e *CancelOfferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { BalanceDelta: types.ConstructAccountAsset( offerAssetId, types.ZeroBigInt, - types.ZeroBigInt, nOffer, ).String(), Order: order, @@ -227,7 +225,6 @@ func (e *CancelOfferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: gasAccount.Nonce, diff --git a/core/executor/create_collection_executor.go b/core/executor/create_collection_executor.go index 71ae8baaf..1e9f34e8d 100644 --- a/core/executor/create_collection_executor.go +++ b/core/executor/create_collection_executor.go @@ -184,7 +184,6 @@ func (e *CreateCollectionExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: fromAccount.Nonce, @@ -209,7 +208,6 @@ func (e *CreateCollectionExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: gasAccount.Nonce, diff --git a/core/executor/create_pair_executor.go b/core/executor/create_pair_executor.go deleted file mode 100644 index 25c66f699..000000000 --- a/core/executor/create_pair_executor.go +++ /dev/null @@ -1,153 +0,0 @@ -package executor - -import ( - "bytes" - "encoding/json" - "errors" - "math/big" - - "github.com/zeromicro/go-zero/core/logx" - "github.com/zeromicro/go-zero/core/stores/sqlx" - - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - "github.com/bnb-chain/zkbnb/common" - "github.com/bnb-chain/zkbnb/dao/liquidity" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -type CreatePairExecutor struct { - BaseExecutor - - txInfo *txtypes.CreatePairTxInfo -} - -func NewCreatePairExecutor(bc IBlockchain, tx *tx.Tx) (TxExecutor, error) { - txInfo, err := types.ParseCreatePairTxInfo(tx.TxInfo) - if err != nil { - logx.Errorf("parse create pair tx failed: %s", err.Error()) - return nil, errors.New("invalid tx info") - } - - return &CreatePairExecutor{ - BaseExecutor: NewBaseExecutor(bc, tx, txInfo), - txInfo: txInfo, - }, nil -} - -func (e *CreatePairExecutor) Prepare() error { - // Mark the tree states that would be affected in this executor. - e.MarkLiquidityDirty(e.txInfo.PairIndex) - return e.BaseExecutor.Prepare() -} - -func (e *CreatePairExecutor) VerifyInputs(skipGasAmtChk bool) error { - bc := e.bc - txInfo := e.txInfo - - _, err := bc.DB().LiquidityModel.GetLiquidityByIndex(txInfo.PairIndex) - if err != sqlx.ErrNotFound { - return errors.New("invalid pair index, already registered") - } - - for index := range bc.StateDB().PendingNewLiquidityMap { - if txInfo.PairIndex == index { - return errors.New("invalid pair index, already registered") - } - } - - return nil -} - -func (e *CreatePairExecutor) ApplyTransaction() error { - txInfo := e.txInfo - - newLiquidity := &liquidity.Liquidity{ - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetAId, - AssetA: types.ZeroBigIntString, - AssetBId: txInfo.AssetBId, - AssetB: types.ZeroBigIntString, - LpAmount: types.ZeroBigIntString, - KLast: types.ZeroBigIntString, - TreasuryAccountIndex: txInfo.TreasuryAccountIndex, - FeeRate: txInfo.FeeRate, - TreasuryRate: txInfo.TreasuryRate, - } - - stateCache := e.bc.StateDB() - stateCache.SetPendingNewLiquidity(txInfo.PairIndex, newLiquidity) - return e.BaseExecutor.ApplyTransaction() -} - -func (e *CreatePairExecutor) GeneratePubData() error { - txInfo := e.txInfo - - var buf bytes.Buffer - buf.WriteByte(uint8(types.TxTypeCreatePair)) - buf.Write(common.Uint16ToBytes(uint16(txInfo.PairIndex))) - buf.Write(common.Uint16ToBytes(uint16(txInfo.AssetAId))) - buf.Write(common.Uint16ToBytes(uint16(txInfo.AssetBId))) - buf.Write(common.Uint16ToBytes(uint16(txInfo.FeeRate))) - buf.Write(common.Uint32ToBytes(uint32(txInfo.TreasuryAccountIndex))) - buf.Write(common.Uint16ToBytes(uint16(txInfo.TreasuryRate))) - chunk := common.SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - pubData := buf.Bytes() - - stateCache := e.bc.StateDB() - stateCache.PriorityOperations++ - stateCache.PubDataOffset = append(stateCache.PubDataOffset, uint32(len(stateCache.PubData))) - stateCache.PubData = append(stateCache.PubData, pubData...) - return nil -} - -func (e *CreatePairExecutor) GetExecutedTx() (*tx.Tx, error) { - txInfoBytes, err := json.Marshal(e.txInfo) - if err != nil { - logx.Errorf("unable to marshal tx, err: %s", err.Error()) - return nil, errors.New("unmarshal tx failed") - } - - e.tx.TxInfo = string(txInfoBytes) - e.tx.PairIndex = e.txInfo.PairIndex - return e.BaseExecutor.GetExecutedTx() -} - -func (e *CreatePairExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { - txInfo := e.txInfo - baseLiquidity := types.EmptyLiquidityInfo(txInfo.PairIndex) - deltaLiquidity := &types.LiquidityInfo{ - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetAId, - AssetA: big.NewInt(0), - AssetBId: txInfo.AssetBId, - AssetB: big.NewInt(0), - LpAmount: big.NewInt(0), - KLast: big.NewInt(0), - FeeRate: txInfo.FeeRate, - TreasuryAccountIndex: txInfo.TreasuryAccountIndex, - TreasuryRate: txInfo.TreasuryRate, - } - - txDetail := &tx.TxDetail{ - AssetId: txInfo.PairIndex, - AssetType: types.LiquidityAssetType, - AccountIndex: types.NilAccountIndex, - AccountName: types.NilAccountName, - Balance: baseLiquidity.String(), - BalanceDelta: deltaLiquidity.String(), - Order: 0, - AccountOrder: types.NilAccountOrder, - Nonce: types.NilNonce, - CollectionNonce: types.NilCollectionNonce, - } - - return []*tx.TxDetail{txDetail}, nil -} diff --git a/core/executor/deposit_executor.go b/core/executor/deposit_executor.go index 108a57b3e..1ed405f75 100644 --- a/core/executor/deposit_executor.go +++ b/core/executor/deposit_executor.go @@ -143,7 +143,6 @@ func (e *DepositExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { deltaBalance := &types.AccountAsset{ AssetId: txInfo.AssetId, Balance: txInfo.AssetAmount, - LpAmount: big.NewInt(0), OfferCanceledOrFinalized: big.NewInt(0), } txDetail := &tx.TxDetail{ diff --git a/core/executor/deposit_nft_executor.go b/core/executor/deposit_nft_executor.go index 1d973da0d..2c6642235 100644 --- a/core/executor/deposit_nft_executor.go +++ b/core/executor/deposit_nft_executor.go @@ -185,7 +185,6 @@ func (e *DepositNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { deltaBalance := &types.AccountAsset{ AssetId: 0, Balance: big.NewInt(0), - LpAmount: big.NewInt(0), OfferCanceledOrFinalized: big.NewInt(0), } txDetails = append(txDetails, &tx.TxDetail{ diff --git a/core/executor/executor.go b/core/executor/executor.go index 19304bc2f..436f364cf 100644 --- a/core/executor/executor.go +++ b/core/executor/executor.go @@ -32,22 +32,12 @@ func NewTxExecutor(bc IBlockchain, tx *tx.Tx) (TxExecutor, error) { switch tx.TxType { case types.TxTypeRegisterZns: return NewRegisterZnsExecutor(bc, tx) - case types.TxTypeCreatePair: - return NewCreatePairExecutor(bc, tx) - case types.TxTypeUpdatePairRate: - return NewUpdatePairRateExecutor(bc, tx) case types.TxTypeDeposit: return NewDepositExecutor(bc, tx) case types.TxTypeDepositNft: return NewDepositNftExecutor(bc, tx) case types.TxTypeTransfer: return NewTransferExecutor(bc, tx) - case types.TxTypeSwap: - return NewSwapExecutor(bc, tx) - case types.TxTypeAddLiquidity: - return NewAddLiquidityExecutor(bc, tx) - case types.TxTypeRemoveLiquidity: - return NewRemoveLiquidityExecutor(bc, tx) case types.TxTypeWithdraw: return NewWithdrawExecutor(bc, tx) case types.TxTypeCreateCollection: diff --git a/core/executor/full_exit_executor.go b/core/executor/full_exit_executor.go index 4a5549b43..2d896b7d3 100644 --- a/core/executor/full_exit_executor.go +++ b/core/executor/full_exit_executor.go @@ -152,7 +152,6 @@ func (e *FullExitExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { deltaBalance := &types.AccountAsset{ AssetId: txInfo.AssetId, Balance: ffmath.Neg(txInfo.AssetAmount), - LpAmount: big.NewInt(0), OfferCanceledOrFinalized: big.NewInt(0), } txDetail := &tx.TxDetail{ diff --git a/core/executor/full_exit_nft_executor.go b/core/executor/full_exit_nft_executor.go index d6d09c9c8..ff306c424 100644 --- a/core/executor/full_exit_nft_executor.go +++ b/core/executor/full_exit_nft_executor.go @@ -238,7 +238,6 @@ func (e *FullExitNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { emptyDelta := &types.AccountAsset{ AssetId: 0, Balance: big.NewInt(0), - LpAmount: big.NewInt(0), OfferCanceledOrFinalized: big.NewInt(0), } txDetails = append(txDetails, &tx.TxDetail{ diff --git a/core/executor/mint_nft_executor.go b/core/executor/mint_nft_executor.go index 7cd69d4c6..1d9694ac6 100644 --- a/core/executor/mint_nft_executor.go +++ b/core/executor/mint_nft_executor.go @@ -189,7 +189,6 @@ func (e *MintNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: creatorAccount.Nonce, @@ -214,7 +213,6 @@ func (e *MintNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, types.ZeroBigInt, types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: toAccount.Nonce, @@ -261,7 +259,6 @@ func (e *MintNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: gasAccount.Nonce, diff --git a/core/executor/remove_liquidity_executor.go b/core/executor/remove_liquidity_executor.go deleted file mode 100644 index 3463cbb23..000000000 --- a/core/executor/remove_liquidity_executor.go +++ /dev/null @@ -1,523 +0,0 @@ -package executor - -import ( - "bytes" - "encoding/json" - "math/big" - - "github.com/pkg/errors" - "github.com/zeromicro/go-zero/core/logx" - - "github.com/bnb-chain/zkbnb-crypto/ffmath" - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - common2 "github.com/bnb-chain/zkbnb/common" - "github.com/bnb-chain/zkbnb/common/chain" - "github.com/bnb-chain/zkbnb/dao/liquidity" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -type RemoveLiquidityExecutor struct { - BaseExecutor - - txInfo *txtypes.RemoveLiquidityTxInfo - - newPoolInfo *types.LiquidityInfo -} - -func NewRemoveLiquidityExecutor(bc IBlockchain, tx *tx.Tx) (TxExecutor, error) { - txInfo, err := types.ParseRemoveLiquidityTxInfo(tx.TxInfo) - if err != nil { - logx.Errorf("parse transfer tx failed: %s", err.Error()) - return nil, errors.New("invalid tx info") - } - - return &RemoveLiquidityExecutor{ - BaseExecutor: NewBaseExecutor(bc, tx, txInfo), - txInfo: txInfo, - }, nil -} - -func (e *RemoveLiquidityExecutor) Prepare() error { - txInfo := e.txInfo - - err := e.bc.StateDB().PrepareLiquidity(txInfo.PairIndex) - if err != nil { - logx.Errorf("prepare liquidity failed: %s", err.Error()) - return err - } - err = e.bc.StateDB().PrepareAccountsAndAssets(map[int64]map[int64]bool{ - txInfo.FromAccountIndex: { - txInfo.PairIndex: true, - }, - }) - if err != nil { - return err - } - err = e.fillTxInfo() - if err != nil { - return err - } - - // Mark the tree states that would be affected in this executor. - e.MarkLiquidityDirty(txInfo.PairIndex) - e.MarkAccountAssetsDirty(txInfo.FromAccountIndex, []int64{txInfo.GasFeeAssetId, txInfo.AssetAId, txInfo.AssetBId, txInfo.PairIndex}) - liquidity, err := e.bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - e.MarkAccountAssetsDirty(liquidity.TreasuryAccountIndex, []int64{txInfo.PairIndex}) - e.MarkAccountAssetsDirty(txInfo.GasAccountIndex, []int64{txInfo.GasFeeAssetId}) - err = e.BaseExecutor.Prepare() - if err != nil { - return err - } - - return nil -} - -func (e *RemoveLiquidityExecutor) VerifyInputs(skipGasAmtChk bool) error { - bc := e.bc - txInfo := e.txInfo - - err := e.BaseExecutor.VerifyInputs(skipGasAmtChk) - if err != nil { - return err - } - - fromAccount, err := bc.StateDB().GetFormatAccount(txInfo.FromAccountIndex) - if err != nil { - return err - } - if fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance.Cmp(txInfo.GasFeeAssetAmount) < 0 { - return errors.New("invalid gas asset amount") - } - - liquidityModel, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - liquidityInfo, err := constructLiquidityInfo(liquidityModel) - if err != nil { - logx.Errorf("construct liquidity info error, err: %v", err) - return err - } - if liquidityInfo.AssetA == nil || liquidityInfo.AssetA.Cmp(types.ZeroBigInt) == 0 || - liquidityInfo.AssetB == nil || liquidityInfo.AssetB.Cmp(types.ZeroBigInt) == 0 || - liquidityInfo.LpAmount == nil || liquidityInfo.LpAmount.Cmp(types.ZeroBigInt) == 0 { - return errors.New("invalid pool liquidity") - } - - return nil -} - -func (e *RemoveLiquidityExecutor) fillTxInfo() error { - bc := e.bc - txInfo := e.txInfo - - fromAccount, err := bc.StateDB().GetFormatAccount(txInfo.FromAccountIndex) - if err != nil { - return err - } - liquidityModel, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - - liquidityInfo, err := constructLiquidityInfo(liquidityModel) - if err != nil { - logx.Errorf("construct liquidity info error, err: %v", err) - return err - } - - assetAAmount, assetBAmount, err := chain.ComputeRemoveLiquidityAmount(liquidityInfo, txInfo.LpAmount) - if err != nil { - return err - } - - if assetAAmount.Cmp(txInfo.AssetAMinAmount) < 0 || assetBAmount.Cmp(txInfo.AssetBMinAmount) < 0 { - return errors.New("invalid asset min amount") - } - - if fromAccount.AssetInfo[txInfo.PairIndex].LpAmount.Cmp(txInfo.LpAmount) < 0 { - return errors.New("invalid lp amount") - } - - txInfo.AssetAAmountDelta = assetAAmount - txInfo.AssetBAmountDelta = assetBAmount - txInfo.AssetAId = liquidityInfo.AssetAId - txInfo.AssetBId = liquidityInfo.AssetBId - - poolAssetADelta := ffmath.Neg(txInfo.AssetAAmountDelta) - poolAssetBDelta := ffmath.Neg(txInfo.AssetBAmountDelta) - finalPoolA := ffmath.Add(liquidityInfo.AssetA, poolAssetADelta) - finalPoolB := ffmath.Add(liquidityInfo.AssetB, poolAssetBDelta) - lpDeltaForTreasuryAccount, err := chain.ComputeSLp(liquidityInfo.AssetA, liquidityInfo.AssetB, liquidityInfo.KLast, liquidityInfo.FeeRate, liquidityInfo.TreasuryRate) - if err != nil { - return err - } - - // set tx info - txInfo.KLast, err = common2.CleanPackedAmount(ffmath.Multiply(finalPoolA, finalPoolB)) - if err != nil { - return err - } - txInfo.TreasuryAmount = lpDeltaForTreasuryAccount - - return nil -} - -func (e *RemoveLiquidityExecutor) ApplyTransaction() error { - bc := e.bc - txInfo := e.txInfo - - // apply changes - fromAccount, err := bc.StateDB().GetFormatAccount(txInfo.FromAccountIndex) - if err != nil { - return err - } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } - liquidityModel, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - treasuryAccount, err := bc.StateDB().GetFormatAccount(liquidityModel.TreasuryAccountIndex) - if err != nil { - return err - } - - fromAccount.AssetInfo[txInfo.AssetAId].Balance = ffmath.Add(fromAccount.AssetInfo[txInfo.AssetAId].Balance, txInfo.AssetAAmountDelta) - fromAccount.AssetInfo[txInfo.AssetBId].Balance = ffmath.Add(fromAccount.AssetInfo[txInfo.AssetBId].Balance, txInfo.AssetBAmountDelta) - fromAccount.AssetInfo[txInfo.PairIndex].LpAmount = ffmath.Sub(fromAccount.AssetInfo[txInfo.PairIndex].LpAmount, txInfo.LpAmount) - treasuryAccount.AssetInfo[txInfo.PairIndex].LpAmount = ffmath.Add(treasuryAccount.AssetInfo[txInfo.PairIndex].LpAmount, txInfo.TreasuryAmount) - fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - fromAccount.Nonce++ - - stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(fromAccount.AccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(treasuryAccount.AccountIndex, treasuryAccount) - stateCache.SetPendingUpdateAccount(gasAccount.AccountIndex, gasAccount) - stateCache.SetPendingUpdateLiquidity(txInfo.PairIndex, &liquidity.Liquidity{ - Model: liquidityModel.Model, - PairIndex: e.newPoolInfo.PairIndex, - AssetAId: liquidityModel.AssetAId, - AssetA: e.newPoolInfo.AssetA.String(), - AssetBId: liquidityModel.AssetBId, - AssetB: e.newPoolInfo.AssetB.String(), - LpAmount: e.newPoolInfo.LpAmount.String(), - KLast: e.newPoolInfo.KLast.String(), - FeeRate: e.newPoolInfo.FeeRate, - TreasuryAccountIndex: e.newPoolInfo.TreasuryAccountIndex, - TreasuryRate: e.newPoolInfo.TreasuryRate, - }) - return e.BaseExecutor.ApplyTransaction() -} - -func (e *RemoveLiquidityExecutor) GeneratePubData() error { - txInfo := e.txInfo - - var buf bytes.Buffer - buf.WriteByte(uint8(types.TxTypeRemoveLiquidity)) - buf.Write(common2.Uint32ToBytes(uint32(txInfo.FromAccountIndex))) - buf.Write(common2.Uint16ToBytes(uint16(txInfo.PairIndex))) - packedAssetAAmountBytes, err := common2.AmountToPackedAmountBytes(txInfo.AssetAAmountDelta) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(packedAssetAAmountBytes) - packedAssetBAmountBytes, err := common2.AmountToPackedAmountBytes(txInfo.AssetBAmountDelta) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(packedAssetBAmountBytes) - LpAmountBytes, err := common2.AmountToPackedAmountBytes(txInfo.LpAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(LpAmountBytes) - KLastBytes, err := common2.AmountToPackedAmountBytes(txInfo.KLast) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(KLastBytes) - chunk1 := common2.SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - treasuryAmountBytes, err := common2.AmountToPackedAmountBytes(txInfo.TreasuryAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(treasuryAmountBytes) - buf.Write(common2.Uint32ToBytes(uint32(txInfo.GasAccountIndex))) - buf.Write(common2.Uint16ToBytes(uint16(txInfo.GasFeeAssetId))) - packedFeeBytes, err := common2.FeeToPackedFeeBytes(txInfo.GasFeeAssetAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed fee amount: %s", err.Error()) - return err - } - buf.Write(packedFeeBytes) - chunk2 := common2.PrefixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk1) - buf.Write(chunk2) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - pubData := buf.Bytes() - - stateCache := e.bc.StateDB() - stateCache.PubData = append(stateCache.PubData, pubData...) - return nil -} - -func (e *RemoveLiquidityExecutor) GetExecutedTx() (*tx.Tx, error) { - txInfoBytes, err := json.Marshal(e.txInfo) - if err != nil { - logx.Errorf("unable to marshal tx, err: %s", err.Error()) - return nil, errors.New("unmarshal tx failed") - } - - e.tx.TxInfo = string(txInfoBytes) - e.tx.GasFeeAssetId = e.txInfo.GasFeeAssetId - e.tx.GasFee = e.txInfo.GasFeeAssetAmount.String() - e.tx.PairIndex = e.txInfo.PairIndex - e.tx.TxAmount = e.txInfo.LpAmount.String() - return e.BaseExecutor.GetExecutedTx() -} - -func (e *RemoveLiquidityExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { - txInfo := e.txInfo - - liquidityModel, err := e.bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return nil, err - } - liquidityInfo, err := constructLiquidityInfo(liquidityModel) - if err != nil { - logx.Errorf("construct liquidity info error, err: %v", err) - return nil, err - } - - copiedAccounts, err := e.bc.StateDB().DeepCopyAccounts([]int64{txInfo.FromAccountIndex, txInfo.GasAccountIndex, liquidityInfo.TreasuryAccountIndex}) - if err != nil { - return nil, err - } - - fromAccount := copiedAccounts[txInfo.FromAccountIndex] - gasAccount := copiedAccounts[txInfo.GasAccountIndex] - treasuryAccount := copiedAccounts[liquidityInfo.TreasuryAccountIndex] - - txDetails := make([]*tx.TxDetail, 0, 4) - // from account asset A - order := int64(0) - accountOrder := int64(0) - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.AssetAId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.AssetAId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.AssetAId, - txInfo.AssetAAmountDelta, - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - fromAccount.AssetInfo[txInfo.AssetAId].Balance = ffmath.Add(fromAccount.AssetInfo[txInfo.AssetAId].Balance, txInfo.AssetAAmountDelta) - if fromAccount.AssetInfo[txInfo.AssetAId].Balance.Cmp(big.NewInt(0)) < 0 { - return nil, errors.New("insufficient asset a balance") - } - - // from account asset B - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.AssetBId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.AssetBId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.AssetBId, - txInfo.AssetBAmountDelta, - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - fromAccount.AssetInfo[txInfo.AssetBId].Balance = ffmath.Add(fromAccount.AssetInfo[txInfo.AssetBId].Balance, txInfo.AssetBAmountDelta) - if fromAccount.AssetInfo[txInfo.AssetBId].Balance.Cmp(types.ZeroBigInt) < 0 { - return nil, errors.New("insufficient asset b balance") - } - - // from account asset gas - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.GasFeeAssetId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.GasFeeAssetId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, - ffmath.Neg(txInfo.GasFeeAssetAmount), - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - if fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance.Cmp(types.ZeroBigInt) < 0 { - return nil, errors.New("insufficient gas asset balance") - } - - // from account lp - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.PairIndex, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.PairIndex].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.PairIndex, - types.ZeroBigInt, - ffmath.Neg(txInfo.LpAmount), - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - fromAccount.AssetInfo[txInfo.PairIndex].LpAmount = ffmath.Sub(fromAccount.AssetInfo[txInfo.PairIndex].LpAmount, txInfo.LpAmount) - if fromAccount.AssetInfo[txInfo.PairIndex].LpAmount.Cmp(types.ZeroBigInt) < 0 { - return nil, errors.New("insufficient lp amount") - } - - // treasury account - order++ - accountOrder++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.PairIndex, - AssetType: types.FungibleAssetType, - AccountIndex: treasuryAccount.AccountIndex, - AccountName: treasuryAccount.AccountName, - Balance: treasuryAccount.AssetInfo[txInfo.PairIndex].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.PairIndex, types.ZeroBigInt, txInfo.TreasuryAmount, types.ZeroBigInt, - ).String(), - Order: order, - Nonce: treasuryAccount.Nonce, - AccountOrder: accountOrder, - CollectionNonce: treasuryAccount.CollectionNonce, - }) - treasuryAccount.AssetInfo[txInfo.PairIndex].LpAmount = ffmath.Add(treasuryAccount.AssetInfo[txInfo.PairIndex].LpAmount, txInfo.TreasuryAmount) - - // pool account info - liquidity, err := e.bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return nil, err - } - basePool, err := types.ConstructLiquidityInfo( - liquidity.PairIndex, - liquidity.AssetAId, - liquidity.AssetA, - liquidity.AssetBId, - liquidity.AssetB, - liquidity.LpAmount, - liquidity.KLast, - liquidity.FeeRate, - liquidity.TreasuryAccountIndex, - liquidity.TreasuryRate, - ) - if err != nil { - return nil, err - } - - finalPoolA := ffmath.Add(liquidityInfo.AssetA, ffmath.Neg(txInfo.AssetAAmountDelta)) - finalPoolB := ffmath.Add(liquidityInfo.AssetB, ffmath.Neg(txInfo.AssetBAmountDelta)) - poolDeltaForToAccount := &types.LiquidityInfo{ - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetAId, - AssetA: ffmath.Neg(txInfo.AssetAAmountDelta), - AssetBId: txInfo.AssetBId, - AssetB: ffmath.Neg(txInfo.AssetBAmountDelta), - LpAmount: ffmath.Neg(txInfo.LpAmount), - KLast: ffmath.Multiply(finalPoolA, finalPoolB), - FeeRate: liquidityInfo.FeeRate, - TreasuryAccountIndex: liquidityInfo.TreasuryAccountIndex, - TreasuryRate: liquidityInfo.TreasuryRate, - } - newPool, err := chain.ComputeNewBalance(types.LiquidityAssetType, basePool.String(), poolDeltaForToAccount.String()) - if err != nil { - return nil, err - } - - newPoolInfo, err := types.ParseLiquidityInfo(newPool) - if err != nil { - return nil, err - } - e.newPoolInfo = newPoolInfo - if newPoolInfo.AssetA.Cmp(types.ZeroBigInt) <= 0 || - newPoolInfo.AssetB.Cmp(types.ZeroBigInt) <= 0 || - newPoolInfo.LpAmount.Cmp(types.ZeroBigInt) < 0 || - newPoolInfo.KLast.Cmp(types.ZeroBigInt) <= 0 { - return nil, errors.New("invalid new pool") - } - - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.PairIndex, - AssetType: types.LiquidityAssetType, - AccountIndex: types.NilAccountIndex, - AccountName: types.NilAccountName, - Balance: basePool.String(), - BalanceDelta: poolDeltaForToAccount.String(), - Order: order, - Nonce: types.NilNonce, - AccountOrder: types.NilAccountOrder, - CollectionNonce: types.NilCollectionNonce, - }) - - // gas account asset gas - order++ - accountOrder++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.GasFeeAssetId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.GasAccountIndex, - AccountName: gasAccount.AccountName, - Balance: gasAccount.AssetInfo[txInfo.GasFeeAssetId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, - txInfo.GasFeeAssetAmount, - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: gasAccount.Nonce, - CollectionNonce: gasAccount.CollectionNonce, - }) - return txDetails, nil -} diff --git a/core/executor/swap_executor.go b/core/executor/swap_executor.go deleted file mode 100644 index 2358f7be8..000000000 --- a/core/executor/swap_executor.go +++ /dev/null @@ -1,457 +0,0 @@ -package executor - -import ( - "bytes" - "encoding/json" - "math/big" - - "github.com/pkg/errors" - "github.com/zeromicro/go-zero/core/logx" - - "github.com/bnb-chain/zkbnb-crypto/ffmath" - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - common2 "github.com/bnb-chain/zkbnb/common" - "github.com/bnb-chain/zkbnb/common/chain" - "github.com/bnb-chain/zkbnb/dao/liquidity" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -type SwapExecutor struct { - BaseExecutor - - txInfo *txtypes.SwapTxInfo - - newPoolInfo *types.LiquidityInfo -} - -func NewSwapExecutor(bc IBlockchain, tx *tx.Tx) (TxExecutor, error) { - txInfo, err := types.ParseSwapTxInfo(tx.TxInfo) - if err != nil { - logx.Errorf("parse transfer tx failed: %s", err.Error()) - return nil, errors.New("invalid tx info") - } - - return &SwapExecutor{ - BaseExecutor: NewBaseExecutor(bc, tx, txInfo), - txInfo: txInfo, - }, nil -} - -func (e *SwapExecutor) Prepare() error { - txInfo := e.txInfo - - err := e.bc.StateDB().PrepareLiquidity(txInfo.PairIndex) - if err != nil { - logx.Errorf("prepare liquidity failed: %s", err.Error()) - return errors.New("internal error") - } - - err = e.fillTxInfo() - if err != nil { - return err - } - - // Mark the tree states that would be affected in this executor. - e.MarkLiquidityDirty(txInfo.PairIndex) - e.MarkAccountAssetsDirty(txInfo.FromAccountIndex, []int64{txInfo.GasFeeAssetId, txInfo.AssetAId, txInfo.AssetBId}) - e.MarkAccountAssetsDirty(txInfo.GasAccountIndex, []int64{txInfo.GasFeeAssetId}) - err = e.BaseExecutor.Prepare() - if err != nil { - return err - } - - return nil -} - -func (e *SwapExecutor) VerifyInputs(skipGasAmtChk bool) error { - bc := e.bc - txInfo := e.txInfo - - err := e.BaseExecutor.VerifyInputs(skipGasAmtChk) - if err != nil { - return err - } - - fromAccount, err := bc.StateDB().GetFormatAccount(txInfo.FromAccountIndex) - if err != nil { - return err - } - if txInfo.GasFeeAssetId != txInfo.AssetAId { - if fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance.Cmp(txInfo.GasFeeAssetAmount) < 0 { - return errors.New("invalid gas asset amount") - } - if fromAccount.AssetInfo[txInfo.AssetAId].Balance.Cmp(txInfo.AssetAAmount) < 0 { - return errors.New("invalid asset amount") - } - } else { - deltaBalance := ffmath.Add(txInfo.AssetAAmount, txInfo.GasFeeAssetAmount) - if fromAccount.AssetInfo[txInfo.AssetAId].Balance.Cmp(deltaBalance) < 0 { - return errors.New("invalid asset amount") - } - } - - liquidityModel, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - liquidityInfo, err := constructLiquidityInfo(liquidityModel) - if err != nil { - logx.Errorf("construct liquidity info error, err: %v", err) - return errors.New("internal error") - } - if !((liquidityModel.AssetAId == txInfo.AssetAId && liquidityModel.AssetBId == txInfo.AssetBId) || - (liquidityModel.AssetAId == txInfo.AssetBId && liquidityModel.AssetBId == txInfo.AssetAId)) { - return errors.New("invalid asset ids") - } - if liquidityInfo.AssetA == nil || liquidityInfo.AssetA.Cmp(types.ZeroBigInt) == 0 || - liquidityInfo.AssetB == nil || liquidityInfo.AssetB.Cmp(types.ZeroBigInt) == 0 { - return errors.New("liquidity is empty") - } - - return nil -} - -func constructLiquidityInfo(liquidity *liquidity.Liquidity) (*types.LiquidityInfo, error) { - return types.ConstructLiquidityInfo( - liquidity.PairIndex, - liquidity.AssetAId, - liquidity.AssetA, - liquidity.AssetBId, - liquidity.AssetB, - liquidity.LpAmount, - liquidity.KLast, - liquidity.FeeRate, - liquidity.TreasuryAccountIndex, - liquidity.TreasuryRate, - ) -} - -func (e *SwapExecutor) ApplyTransaction() error { - bc := e.bc - txInfo := e.txInfo - - // apply changes - fromAccount, err := bc.StateDB().GetFormatAccount(txInfo.FromAccountIndex) - if err != nil { - return err - } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } - - fromAccount.AssetInfo[txInfo.AssetAId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.AssetAId].Balance, txInfo.AssetAAmount) - fromAccount.AssetInfo[txInfo.AssetBId].Balance = ffmath.Add(fromAccount.AssetInfo[txInfo.AssetBId].Balance, txInfo.AssetBAmountDelta) - fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - fromAccount.Nonce++ - - liquidityModel, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - - stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(txInfo.FromAccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(txInfo.GasAccountIndex, gasAccount) - stateCache.SetPendingUpdateLiquidity(txInfo.PairIndex, &liquidity.Liquidity{ - Model: liquidityModel.Model, - PairIndex: e.newPoolInfo.PairIndex, - AssetAId: liquidityModel.AssetAId, - AssetA: e.newPoolInfo.AssetA.String(), - AssetBId: liquidityModel.AssetBId, - AssetB: e.newPoolInfo.AssetB.String(), - LpAmount: e.newPoolInfo.LpAmount.String(), - KLast: e.newPoolInfo.KLast.String(), - FeeRate: e.newPoolInfo.FeeRate, - TreasuryAccountIndex: e.newPoolInfo.TreasuryAccountIndex, - TreasuryRate: e.newPoolInfo.TreasuryRate, - }) - return e.BaseExecutor.ApplyTransaction() -} - -func (e *SwapExecutor) fillTxInfo() error { - bc := e.bc - txInfo := e.txInfo - - liquidityModel, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - - liquidityInfo, err := constructLiquidityInfo(liquidityModel) - if err != nil { - logx.Errorf("construct liquidity info error, err: %v", err) - return err - } - - // add details to tx info - var toDelta *big.Int - if liquidityInfo.AssetAId == txInfo.AssetAId && liquidityInfo.AssetBId == txInfo.AssetBId { - toDelta, _, err = chain.ComputeDelta( - liquidityInfo.AssetA, - liquidityInfo.AssetB, - liquidityInfo.AssetAId, - liquidityInfo.AssetBId, - txInfo.AssetAId, - true, - txInfo.AssetAAmount, - liquidityInfo.FeeRate, - ) - if err != nil { - return err - } - } else if liquidityInfo.AssetAId == txInfo.AssetBId && liquidityInfo.AssetBId == txInfo.AssetAId { - toDelta, _, err = chain.ComputeDelta( - liquidityInfo.AssetA, - liquidityInfo.AssetB, - liquidityInfo.AssetAId, - liquidityInfo.AssetBId, - txInfo.AssetBId, - true, - txInfo.AssetAAmount, - liquidityInfo.FeeRate, - ) - if err != nil { - return err - } - } - - if toDelta.Cmp(txInfo.AssetBMinAmount) < 0 { - return errors.New("invalid AssetBMinAmount") - } - txInfo.AssetBAmountDelta = toDelta - - return nil -} - -func (e *SwapExecutor) GeneratePubData() error { - txInfo := e.txInfo - - var buf bytes.Buffer - buf.WriteByte(uint8(types.TxTypeSwap)) - buf.Write(common2.Uint32ToBytes(uint32(txInfo.FromAccountIndex))) - buf.Write(common2.Uint16ToBytes(uint16(txInfo.PairIndex))) - buf.Write(common2.Uint16ToBytes(uint16(txInfo.AssetAId))) - packedAssetAAmountBytes, err := common2.AmountToPackedAmountBytes(txInfo.AssetAAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(packedAssetAAmountBytes) - buf.Write(common2.Uint16ToBytes(uint16(txInfo.AssetBId))) - packedAssetBAmountDeltaBytes, err := common2.AmountToPackedAmountBytes(txInfo.AssetBAmountDelta) - if err != nil { - logx.Errorf("unable to convert amount to packed amount: %s", err.Error()) - return err - } - buf.Write(packedAssetBAmountDeltaBytes) - buf.Write(common2.Uint32ToBytes(uint32(txInfo.GasAccountIndex))) - buf.Write(common2.Uint16ToBytes(uint16(txInfo.GasFeeAssetId))) - packedFeeBytes, err := common2.FeeToPackedFeeBytes(txInfo.GasFeeAssetAmount) - if err != nil { - logx.Errorf("unable to convert amount to packed fee amount: %s", err.Error()) - return err - } - buf.Write(packedFeeBytes) - chunk := common2.SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common2.PrefixPaddingBufToChunkSize([]byte{})) - pubData := buf.Bytes() - - stateCache := e.bc.StateDB() - stateCache.PubData = append(stateCache.PubData, pubData...) - return nil -} - -func (e *SwapExecutor) GetExecutedTx() (*tx.Tx, error) { - txInfoBytes, err := json.Marshal(e.txInfo) - if err != nil { - logx.Errorf("unable to marshal tx, err: %s", err.Error()) - return nil, errors.New("unmarshal tx failed") - } - - e.tx.TxInfo = string(txInfoBytes) - e.tx.GasFeeAssetId = e.txInfo.GasFeeAssetId - e.tx.GasFee = e.txInfo.GasFeeAssetAmount.String() - e.tx.PairIndex = e.txInfo.PairIndex - e.tx.TxAmount = e.txInfo.AssetAAmount.String() - return e.BaseExecutor.GetExecutedTx() -} - -func (e *SwapExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { - txInfo := e.txInfo - - copiedAccounts, err := e.bc.StateDB().DeepCopyAccounts([]int64{txInfo.FromAccountIndex, txInfo.GasAccountIndex}) - if err != nil { - return nil, err - } - - fromAccount := copiedAccounts[txInfo.FromAccountIndex] - gasAccount := copiedAccounts[txInfo.GasAccountIndex] - liquidityModel, err := e.bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return nil, err - } - liquidityInfo, err := constructLiquidityInfo(liquidityModel) - if err != nil { - logx.Errorf("construct liquidity info error, err: %v", err) - return nil, err - } - - txDetails := make([]*tx.TxDetail, 0, 4) - // from account asset A - order := int64(0) - accountOrder := int64(0) - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.AssetAId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.AssetAId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.AssetAId, - ffmath.Neg(txInfo.AssetAAmount), - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - fromAccount.AssetInfo[txInfo.AssetAId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.AssetAId].Balance, txInfo.AssetAAmount) - if fromAccount.AssetInfo[txInfo.AssetAId].Balance.Cmp(types.ZeroBigInt) < 0 { - return nil, errors.New("insufficient asset a balance") - } - - // from account asset B - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.AssetBId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.AssetBId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.AssetBId, - txInfo.AssetBAmountDelta, - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - fromAccount.AssetInfo[txInfo.AssetBId].Balance = ffmath.Add(fromAccount.AssetInfo[txInfo.AssetBId].Balance, txInfo.AssetBAmountDelta) - - // from account asset gas - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.GasFeeAssetId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.FromAccountIndex, - AccountName: fromAccount.AccountName, - Balance: fromAccount.AssetInfo[txInfo.GasFeeAssetId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, - ffmath.Neg(txInfo.GasFeeAssetAmount), - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: fromAccount.Nonce, - CollectionNonce: fromAccount.CollectionNonce, - }) - fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - if fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance.Cmp(types.ZeroBigInt) < 0 { - return nil, errors.New("insufficient gas fee balance") - } - - // pool info - var poolDelta *types.LiquidityInfo - poolAssetBDelta := ffmath.Neg(txInfo.AssetBAmountDelta) - if txInfo.AssetAId == liquidityInfo.AssetAId { - poolDelta = &types.LiquidityInfo{ - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetAId, - AssetA: txInfo.AssetAAmount, - AssetBId: txInfo.AssetBId, - AssetB: poolAssetBDelta, - LpAmount: types.ZeroBigInt, - KLast: types.ZeroBigInt, - FeeRate: liquidityInfo.FeeRate, - TreasuryAccountIndex: liquidityInfo.TreasuryAccountIndex, - TreasuryRate: liquidityInfo.TreasuryRate, - } - } else if txInfo.AssetAId == liquidityInfo.AssetBId { - poolDelta = &types.LiquidityInfo{ - PairIndex: txInfo.PairIndex, - AssetAId: txInfo.AssetBId, - AssetA: poolAssetBDelta, - AssetBId: txInfo.AssetAId, - AssetB: txInfo.AssetAAmount, - LpAmount: types.ZeroBigInt, - KLast: types.ZeroBigInt, - FeeRate: liquidityInfo.FeeRate, - TreasuryAccountIndex: liquidityInfo.TreasuryAccountIndex, - TreasuryRate: liquidityInfo.TreasuryRate, - } - } - - newPool, err := chain.ComputeNewBalance( - types.LiquidityAssetType, liquidityInfo.String(), poolDelta.String()) - if err != nil { - return nil, err - } - - nPoolInfo, err := types.ParseLiquidityInfo(newPool) - if err != nil { - return nil, err - } - e.newPoolInfo = nPoolInfo - - order++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.PairIndex, - AssetType: types.LiquidityAssetType, - AccountIndex: types.NilAccountIndex, - AccountName: types.NilAccountName, - Balance: liquidityInfo.String(), - BalanceDelta: poolDelta.String(), - Order: order, - Nonce: 0, - AccountOrder: types.NilAccountOrder, - CollectionNonce: 0, - }) - - // gas account asset gas - order++ - accountOrder++ - txDetails = append(txDetails, &tx.TxDetail{ - AssetId: txInfo.GasFeeAssetId, - AssetType: types.FungibleAssetType, - AccountIndex: txInfo.GasAccountIndex, - AccountName: gasAccount.AccountName, - Balance: gasAccount.AssetInfo[txInfo.GasFeeAssetId].String(), - BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, - txInfo.GasFeeAssetAmount, - types.ZeroBigInt, - types.ZeroBigInt, - ).String(), - Order: order, - AccountOrder: accountOrder, - Nonce: gasAccount.Nonce, - CollectionNonce: gasAccount.CollectionNonce, - }) - return txDetails, nil -} diff --git a/core/executor/transfer_executor.go b/core/executor/transfer_executor.go index 8a62d95cf..860805403 100644 --- a/core/executor/transfer_executor.go +++ b/core/executor/transfer_executor.go @@ -182,7 +182,7 @@ func (e *TransferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: fromAccount.AccountName, Balance: fromAccount.AssetInfo[txInfo.AssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.AssetId, ffmath.Neg(txInfo.AssetAmount), types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.AssetId, ffmath.Neg(txInfo.AssetAmount), types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: fromAccount.Nonce, @@ -198,7 +198,7 @@ func (e *TransferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: fromAccount.AccountName, Balance: fromAccount.AssetInfo[txInfo.GasFeeAssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: fromAccount.Nonce, @@ -215,7 +215,7 @@ func (e *TransferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: toAccount.AccountName, Balance: toAccount.AssetInfo[txInfo.AssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.AssetId, txInfo.AssetAmount, types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.AssetId, txInfo.AssetAmount, types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: toAccount.Nonce, @@ -232,7 +232,7 @@ func (e *TransferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: gasAccount.AccountName, Balance: gasAccount.AssetInfo[txInfo.GasFeeAssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: gasAccount.Nonce, diff --git a/core/executor/transfer_nft_executor.go b/core/executor/transfer_nft_executor.go index 354b2fb80..8966e8401 100644 --- a/core/executor/transfer_nft_executor.go +++ b/core/executor/transfer_nft_executor.go @@ -188,7 +188,6 @@ func (e *TransferNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: fromAccount.Nonce, @@ -213,7 +212,6 @@ func (e *TransferNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, types.ZeroBigInt, types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: toAccount.Nonce, @@ -269,7 +267,6 @@ func (e *TransferNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, Nonce: gasAccount.Nonce, diff --git a/core/executor/update_pair_rate_executor.go b/core/executor/update_pair_rate_executor.go deleted file mode 100644 index d82c958a2..000000000 --- a/core/executor/update_pair_rate_executor.go +++ /dev/null @@ -1,171 +0,0 @@ -package executor - -import ( - "bytes" - "encoding/json" - "errors" - "math/big" - - "github.com/zeromicro/go-zero/core/logx" - - "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" - "github.com/bnb-chain/zkbnb/common" - "github.com/bnb-chain/zkbnb/dao/tx" - "github.com/bnb-chain/zkbnb/types" -) - -type UpdatePairRateExecutor struct { - BaseExecutor - - txInfo *txtypes.UpdatePairRateTxInfo -} - -func NewUpdatePairRateExecutor(bc IBlockchain, tx *tx.Tx) (TxExecutor, error) { - txInfo, err := types.ParseUpdatePairRateTxInfo(tx.TxInfo) - if err != nil { - logx.Errorf("parse update pair rate tx failed: %s", err.Error()) - return nil, errors.New("invalid tx info") - } - - return &UpdatePairRateExecutor{ - BaseExecutor: NewBaseExecutor(bc, tx, txInfo), - txInfo: txInfo, - }, nil -} - -func (e *UpdatePairRateExecutor) Prepare() error { - txInfo := e.txInfo - - err := e.bc.StateDB().PrepareLiquidity(txInfo.PairIndex) - if err != nil { - logx.Errorf("prepare liquidity failed: %s", err.Error()) - return err - } - - // Mark the tree states that would be affected in this executor. - e.MarkLiquidityDirty(txInfo.PairIndex) - return e.BaseExecutor.Prepare() -} - -func (e *UpdatePairRateExecutor) VerifyInputs(skipGasAmtChk bool) error { - bc := e.bc - txInfo := e.txInfo - liquidity, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - - if liquidity.FeeRate == txInfo.FeeRate && - liquidity.TreasuryAccountIndex == txInfo.TreasuryAccountIndex && - liquidity.TreasuryRate == txInfo.TreasuryRate { - return errors.New("invalid update, the same to old") - } - - return nil -} - -func (e *UpdatePairRateExecutor) ApplyTransaction() error { - bc := e.bc - txInfo := e.txInfo - - liquidity, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return err - } - liquidity.FeeRate = txInfo.FeeRate - liquidity.TreasuryAccountIndex = txInfo.TreasuryAccountIndex - liquidity.TreasuryRate = txInfo.TreasuryRate - - stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateLiquidity(txInfo.PairIndex, liquidity) - return e.BaseExecutor.ApplyTransaction() -} - -func (e *UpdatePairRateExecutor) GeneratePubData() error { - txInfo := e.txInfo - - var buf bytes.Buffer - buf.WriteByte(uint8(types.TxTypeUpdatePairRate)) - buf.Write(common.Uint16ToBytes(uint16(txInfo.PairIndex))) - buf.Write(common.Uint16ToBytes(uint16(txInfo.FeeRate))) - buf.Write(common.Uint32ToBytes(uint32(txInfo.TreasuryAccountIndex))) - buf.Write(common.Uint16ToBytes(uint16(txInfo.TreasuryRate))) - chunk := common.SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(common.PrefixPaddingBufToChunkSize([]byte{})) - pubData := buf.Bytes() - - stateCache := e.bc.StateDB() - stateCache.PriorityOperations++ - stateCache.PubDataOffset = append(stateCache.PubDataOffset, uint32(len(stateCache.PubData))) - stateCache.PubData = append(stateCache.PubData, pubData...) - return nil -} - -func (e *UpdatePairRateExecutor) GetExecutedTx() (*tx.Tx, error) { - txInfoBytes, err := json.Marshal(e.txInfo) - if err != nil { - logx.Errorf("unable to marshal tx, err: %s", err.Error()) - return nil, errors.New("unmarshal tx failed") - } - - e.tx.TxInfo = string(txInfoBytes) - e.tx.PairIndex = e.txInfo.PairIndex - return e.BaseExecutor.GetExecutedTx() -} - -func (e *UpdatePairRateExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { - bc := e.bc - txInfo := e.txInfo - liquidity, err := bc.StateDB().GetLiquidity(txInfo.PairIndex) - if err != nil { - return nil, err - } - baseLiquidity, err := types.ConstructLiquidityInfo( - liquidity.PairIndex, - liquidity.AssetAId, - liquidity.AssetA, - liquidity.AssetBId, - liquidity.AssetB, - liquidity.LpAmount, - liquidity.KLast, - liquidity.FeeRate, - liquidity.TreasuryAccountIndex, - liquidity.TreasuryRate, - ) - if err != nil { - return nil, err - } - deltaLiquidity := &types.LiquidityInfo{ - PairIndex: baseLiquidity.PairIndex, - AssetAId: baseLiquidity.AssetAId, - AssetA: big.NewInt(0), - AssetBId: baseLiquidity.AssetBId, - AssetB: big.NewInt(0), - LpAmount: big.NewInt(0), - KLast: baseLiquidity.KLast, - FeeRate: txInfo.FeeRate, - TreasuryAccountIndex: txInfo.TreasuryAccountIndex, - TreasuryRate: txInfo.TreasuryRate, - } - - txDetail := &tx.TxDetail{ - AssetId: txInfo.PairIndex, - AssetType: types.LiquidityAssetType, - AccountIndex: types.NilAccountIndex, - AccountName: types.NilAccountName, - Balance: baseLiquidity.String(), - BalanceDelta: deltaLiquidity.String(), - Order: 0, - AccountOrder: types.NilAccountOrder, - Nonce: types.NilNonce, - CollectionNonce: types.NilCollectionNonce, - } - - return []*tx.TxDetail{txDetail}, nil -} diff --git a/core/executor/withdraw_executor.go b/core/executor/withdraw_executor.go index ce3bae020..7d54cdb43 100644 --- a/core/executor/withdraw_executor.go +++ b/core/executor/withdraw_executor.go @@ -169,7 +169,7 @@ func (e *WithdrawExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: fromAccount.AccountName, Balance: fromAccount.AssetInfo[txInfo.AssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.AssetId, ffmath.Neg(txInfo.AssetAmount), types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.AssetId, ffmath.Neg(txInfo.AssetAmount), types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: fromAccount.Nonce, @@ -189,7 +189,7 @@ func (e *WithdrawExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: fromAccount.AccountName, Balance: fromAccount.AssetInfo[txInfo.GasFeeAssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: fromAccount.Nonce, @@ -210,7 +210,7 @@ func (e *WithdrawExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountName: gasAccount.AccountName, Balance: gasAccount.AssetInfo[txInfo.GasFeeAssetId].String(), BalanceDelta: types.ConstructAccountAsset( - txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt, types.ZeroBigInt).String(), + txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt).String(), Order: order, AccountOrder: accountOrder, Nonce: gasAccount.Nonce, diff --git a/core/executor/withdraw_nft_executor.go b/core/executor/withdraw_nft_executor.go index ca407165b..bebf3cdce 100644 --- a/core/executor/withdraw_nft_executor.go +++ b/core/executor/withdraw_nft_executor.go @@ -230,7 +230,6 @@ func (e *WithdrawNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, ffmath.Neg(txInfo.GasFeeAssetAmount), types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, AccountOrder: accountOrder, @@ -279,7 +278,6 @@ func (e *WithdrawNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, types.ZeroBigInt, types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, AccountOrder: accountOrder, @@ -300,7 +298,6 @@ func (e *WithdrawNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount, types.ZeroBigInt, - types.ZeroBigInt, ).String(), Order: order, AccountOrder: accountOrder, diff --git a/core/statedb/chaindb.go b/core/statedb/chaindb.go index 6268c6bb1..4ad7e512a 100644 --- a/core/statedb/chaindb.go +++ b/core/statedb/chaindb.go @@ -8,7 +8,6 @@ import ( "github.com/bnb-chain/zkbnb/dao/asset" "github.com/bnb-chain/zkbnb/dao/block" "github.com/bnb-chain/zkbnb/dao/compressedblock" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/dao/sysconfig" "github.com/bnb-chain/zkbnb/dao/tx" @@ -22,14 +21,12 @@ type ChainDB struct { TxModel tx.TxModel // State DB - AccountModel account.AccountModel - AccountHistoryModel account.AccountHistoryModel - L2AssetInfoModel asset.AssetModel - LiquidityModel liquidity.LiquidityModel - LiquidityHistoryModel liquidity.LiquidityHistoryModel - L2NftModel nft.L2NftModel - L2NftHistoryModel nft.L2NftHistoryModel - TxPoolModel tx.TxPoolModel + AccountModel account.AccountModel + AccountHistoryModel account.AccountHistoryModel + L2AssetInfoModel asset.AssetModel + L2NftModel nft.L2NftModel + L2NftHistoryModel nft.L2NftHistoryModel + TxPoolModel tx.TxPoolModel // Sys config SysConfigModel sysconfig.SysConfigModel @@ -42,14 +39,12 @@ func NewChainDB(db *gorm.DB) *ChainDB { CompressedBlockModel: compressedblock.NewCompressedBlockModel(db), TxModel: tx.NewTxModel(db), - AccountModel: account.NewAccountModel(db), - AccountHistoryModel: account.NewAccountHistoryModel(db), - L2AssetInfoModel: asset.NewAssetModel(db), - LiquidityModel: liquidity.NewLiquidityModel(db), - LiquidityHistoryModel: liquidity.NewLiquidityHistoryModel(db), - L2NftModel: nft.NewL2NftModel(db), - L2NftHistoryModel: nft.NewL2NftHistoryModel(db), - TxPoolModel: tx.NewTxPoolModel(db), + AccountModel: account.NewAccountModel(db), + AccountHistoryModel: account.NewAccountHistoryModel(db), + L2AssetInfoModel: asset.NewAssetModel(db), + L2NftModel: nft.NewL2NftModel(db), + L2NftHistoryModel: nft.NewL2NftHistoryModel(db), + TxPoolModel: tx.NewTxPoolModel(db), SysConfigModel: sysconfig.NewSysConfigModel(db), } diff --git a/core/statedb/state_cache.go b/core/statedb/state_cache.go index 528a96438..9950e2e7b 100644 --- a/core/statedb/state_cache.go +++ b/core/statedb/state_cache.go @@ -4,7 +4,6 @@ import ( "github.com/ethereum/go-ethereum/common" cryptoTypes "github.com/bnb-chain/zkbnb-crypto/circuit/types" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/dao/tx" "github.com/bnb-chain/zkbnb/types" @@ -21,16 +20,13 @@ type StateCache struct { Txs []*tx.Tx // Record the flat data that should be updated. - PendingNewAccountMap map[int64]*types.AccountInfo - PendingNewLiquidityMap map[int64]*liquidity.Liquidity - PendingNewNftMap map[int64]*nft.L2Nft - PendingUpdateAccountMap map[int64]*types.AccountInfo - PendingUpdateLiquidityMap map[int64]*liquidity.Liquidity - PendingUpdateNftMap map[int64]*nft.L2Nft + PendingNewAccountMap map[int64]*types.AccountInfo + PendingNewNftMap map[int64]*nft.L2Nft + PendingUpdateAccountMap map[int64]*types.AccountInfo + PendingUpdateNftMap map[int64]*nft.L2Nft // Record the tree states that should be updated. dirtyAccountsAndAssetsMap map[int64]map[int64]bool - dirtyLiquidityMap map[int64]bool dirtyNftMap map[int64]bool } @@ -39,12 +35,10 @@ func NewStateCache(stateRoot string) *StateCache { StateRoot: stateRoot, Txs: make([]*tx.Tx, 0), - PendingNewAccountMap: make(map[int64]*types.AccountInfo, 0), - PendingNewLiquidityMap: make(map[int64]*liquidity.Liquidity, 0), - PendingNewNftMap: make(map[int64]*nft.L2Nft, 0), - PendingUpdateAccountMap: make(map[int64]*types.AccountInfo, 0), - PendingUpdateLiquidityMap: make(map[int64]*liquidity.Liquidity, 0), - PendingUpdateNftMap: make(map[int64]*nft.L2Nft, 0), + PendingNewAccountMap: make(map[int64]*types.AccountInfo, 0), + PendingNewNftMap: make(map[int64]*nft.L2Nft, 0), + PendingUpdateAccountMap: make(map[int64]*types.AccountInfo, 0), + PendingUpdateNftMap: make(map[int64]*nft.L2Nft, 0), PubData: make([]byte, 0), PriorityOperations: 0, @@ -53,7 +47,6 @@ func NewStateCache(stateRoot string) *StateCache { PendingOnChainOperationsHash: common.FromHex(types.EmptyStringKeccak), dirtyAccountsAndAssetsMap: make(map[int64]map[int64]bool, 0), - dirtyLiquidityMap: make(map[int64]bool, 0), dirtyNftMap: make(map[int64]bool, 0), } } @@ -81,10 +74,6 @@ func (c *StateCache) MarkAccountAssetsDirty(accountIndex int64, assets []int64) } } -func (c *StateCache) MarkLiquidityDirty(pairIndex int64) { - c.dirtyLiquidityMap[pairIndex] = true -} - func (c *StateCache) MarkNftDirty(nftIndex int64) { c.dirtyNftMap[nftIndex] = true } @@ -101,18 +90,6 @@ func (c *StateCache) GetPendingAccount(accountIndex int64) (*types.AccountInfo, return nil, false } -func (c *StateCache) GetPendingLiquidity(pairIndex int64) (*liquidity.Liquidity, bool) { - liquidity, exist := c.PendingNewLiquidityMap[pairIndex] - if exist { - return liquidity, exist - } - liquidity, exist = c.PendingUpdateLiquidityMap[pairIndex] - if exist { - return liquidity, exist - } - return nil, false -} - func (c *StateCache) GetPendingNft(nftIndex int64) (*nft.L2Nft, bool) { nft, exist := c.PendingNewNftMap[nftIndex] if exist { @@ -133,14 +110,6 @@ func (c *StateCache) SetPendingUpdateAccount(accountIndex int64, account *types. c.PendingUpdateAccountMap[accountIndex] = account } -func (c *StateCache) SetPendingUpdateLiquidity(pairIndex int64, liquidity *liquidity.Liquidity) { - c.PendingUpdateLiquidityMap[pairIndex] = liquidity -} - -func (c *StateCache) SetPendingNewLiquidity(pairIndex int64, liquidity *liquidity.Liquidity) { - c.PendingNewLiquidityMap[pairIndex] = liquidity -} - func (c *StateCache) SetPendingNewNft(nftIndex int64, nft *nft.L2Nft) { c.PendingNewNftMap[nftIndex] = nft } diff --git a/core/statedb/statedb.go b/core/statedb/statedb.go index c17a026bb..a264352e8 100644 --- a/core/statedb/statedb.go +++ b/core/statedb/statedb.go @@ -16,7 +16,6 @@ import ( "github.com/bnb-chain/zkbnb/common/chain" "github.com/bnb-chain/zkbnb/dao/account" "github.com/bnb-chain/zkbnb/dao/dbcache" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/tree" "github.com/bnb-chain/zkbnb/types" @@ -24,16 +23,14 @@ import ( var ( DefaultCacheConfig = CacheConfig{ - AccountCacheSize: 2048, - LiquidityCacheSize: 2048, - NftCacheSize: 2048, + AccountCacheSize: 2048, + NftCacheSize: 2048, } ) type CacheConfig struct { - AccountCacheSize int - LiquidityCacheSize int - NftCacheSize int + AccountCacheSize int + NftCacheSize int } func (c *CacheConfig) sanitize() *CacheConfig { @@ -41,10 +38,6 @@ func (c *CacheConfig) sanitize() *CacheConfig { c.AccountCacheSize = DefaultCacheConfig.AccountCacheSize } - if c.LiquidityCacheSize <= 0 { - c.LiquidityCacheSize = DefaultCacheConfig.LiquidityCacheSize - } - if c.NftCacheSize <= 0 { c.NftCacheSize = DefaultCacheConfig.NftCacheSize } @@ -60,13 +53,11 @@ type StateDB struct { redisCache dbcache.Cache // Flat state - AccountCache *lru.Cache - LiquidityCache *lru.Cache - NftCache *lru.Cache + AccountCache *lru.Cache + NftCache *lru.Cache // Tree state AccountTree bsmt.SparseMerkleTree - LiquidityTree bsmt.SparseMerkleTree NftTree bsmt.SparseMerkleTree AccountAssetTrees *tree.AssetTreeCache TreeCtx *tree.Context @@ -91,15 +82,6 @@ func NewStateDB(treeCtx *tree.Context, chainDb *ChainDB, logx.Error("dbinitializer account tree failed:", err) return nil, err } - liquidityTree, err := tree.InitLiquidityTree( - chainDb.LiquidityHistoryModel, - curHeight, - treeCtx, - ) - if err != nil { - logx.Error("dbinitializer liquidity tree failed:", err) - return nil, err - } nftTree, err := tree.InitNftTree( chainDb.L2NftHistoryModel, curHeight, @@ -116,11 +98,6 @@ func NewStateDB(treeCtx *tree.Context, chainDb *ChainDB, logx.Error("init account cache failed:", err) return nil, err } - liquidityCache, err := lru.New(cacheConfig.LiquidityCacheSize) - if err != nil { - logx.Error("init liquidity cache failed:", err) - return nil, err - } nftCache, err := lru.New(cacheConfig.NftCacheSize) if err != nil { logx.Error("init nft cache failed:", err) @@ -128,15 +105,13 @@ func NewStateDB(treeCtx *tree.Context, chainDb *ChainDB, } return &StateDB{ - StateCache: NewStateCache(stateRoot), - chainDb: chainDb, - redisCache: redisCache, - AccountCache: accountCache, - LiquidityCache: liquidityCache, - NftCache: nftCache, + StateCache: NewStateCache(stateRoot), + chainDb: chainDb, + redisCache: redisCache, + AccountCache: accountCache, + NftCache: nftCache, AccountTree: accountTree, - LiquidityTree: liquidityTree, NftTree: nftTree, AccountAssetTrees: accountAssetTrees, TreeCtx: treeCtx, @@ -149,24 +124,18 @@ func NewStateDBForDryRun(redisCache dbcache.Cache, cacheConfig *CacheConfig, cha logx.Error("init account cache failed:", err) return nil, err } - liquidityCache, err := lru.New(cacheConfig.LiquidityCacheSize) - if err != nil { - logx.Error("init liquidity cache failed:", err) - return nil, err - } nftCache, err := lru.New(cacheConfig.NftCacheSize) if err != nil { logx.Error("init nft cache failed:", err) return nil, err } return &StateDB{ - dryRun: true, - redisCache: redisCache, - chainDb: chainDb, - AccountCache: accountCache, - LiquidityCache: liquidityCache, - NftCache: nftCache, - StateCache: NewStateCache(""), + dryRun: true, + redisCache: redisCache, + chainDb: chainDb, + AccountCache: accountCache, + NftCache: nftCache, + StateCache: NewStateCache(""), }, nil } @@ -224,23 +193,6 @@ func (s *StateDB) GetAccount(accountIndex int64) (*account.Account, error) { return account, nil } -func (s *StateDB) GetLiquidity(pairIndex int64) (*liquidity.Liquidity, error) { - pending, exist := s.StateCache.GetPendingLiquidity(pairIndex) - if exist { - return pending, nil - } - cached, exist := s.LiquidityCache.Get(pairIndex) - if exist { - return cached.(*liquidity.Liquidity), nil - } - liquidity, err := s.chainDb.LiquidityModel.GetLiquidityByIndex(pairIndex) - if err != nil { - return nil, err - } - s.LiquidityCache.Add(pairIndex, liquidity) - return liquidity, nil -} - func (s *StateDB) GetNft(nftIndex int64) (*nft.L2Nft, error) { pending, exist := s.StateCache.GetPendingNft(nftIndex) if exist { @@ -274,17 +226,6 @@ func (s *StateDB) syncPendingAccount(pendingAccount map[int64]*types.AccountInfo return nil } -func (s *StateDB) syncPendingLiquidity(pendingLiquidity map[int64]*liquidity.Liquidity) error { - for index, liquidity := range pendingLiquidity { - err := s.redisCache.Set(context.Background(), dbcache.LiquidityKeyByIndex(index), liquidity) - if err != nil { - return fmt.Errorf("cache to redis failed: %v", err) - } - s.LiquidityCache.Add(index, liquidity) - } - return nil -} - func (s *StateDB) syncPendingNft(pendingNft map[int64]*nft.L2Nft) error { for index, nft := range pendingNft { err := s.redisCache.Set(context.Background(), dbcache.NftKeyByIndex(index), nft) @@ -302,10 +243,6 @@ func (s *StateDB) SyncStateCacheToRedis() error { if err != nil { return err } - err = s.syncPendingLiquidity(s.PendingNewLiquidityMap) - if err != nil { - return err - } err = s.syncPendingNft(s.PendingNewNftMap) if err != nil { return err @@ -316,10 +253,6 @@ func (s *StateDB) SyncStateCacheToRedis() error { if err != nil { return err } - err = s.syncPendingLiquidity(s.PendingUpdateLiquidityMap) - if err != nil { - return err - } err = s.syncPendingNft(s.PendingUpdateNftMap) if err != nil { return err @@ -377,52 +310,6 @@ func (s *StateDB) GetPendingAccount(blockHeight int64) ([]*account.Account, []*a return pendingNewAccount, pendingUpdateAccount, pendingNewAccountHistory, nil } -func (s *StateDB) GetPendingLiquidity(blockHeight int64) ([]*liquidity.Liquidity, []*liquidity.Liquidity, []*liquidity.LiquidityHistory, error) { - pendingNewLiquidity := make([]*liquidity.Liquidity, 0) - pendingUpdateLiquidity := make([]*liquidity.Liquidity, 0) - pendingNewLiquidityHistory := make([]*liquidity.LiquidityHistory, 0) - - for _, newLiquidity := range s.PendingNewLiquidityMap { - pendingNewLiquidity = append(pendingNewLiquidity, newLiquidity) - pendingNewLiquidityHistory = append(pendingNewLiquidityHistory, &liquidity.LiquidityHistory{ - PairIndex: newLiquidity.PairIndex, - AssetAId: newLiquidity.AssetAId, - AssetA: newLiquidity.AssetA, - AssetBId: newLiquidity.AssetBId, - AssetB: newLiquidity.AssetB, - LpAmount: newLiquidity.LpAmount, - KLast: newLiquidity.KLast, - FeeRate: newLiquidity.FeeRate, - TreasuryAccountIndex: newLiquidity.TreasuryAccountIndex, - TreasuryRate: newLiquidity.TreasuryRate, - L2BlockHeight: blockHeight, - }) - } - - for index, newLiquidity := range s.PendingUpdateLiquidityMap { - if _, exist := s.PendingNewLiquidityMap[index]; exist { - continue - } - - pendingUpdateLiquidity = append(pendingUpdateLiquidity, newLiquidity) - pendingNewLiquidityHistory = append(pendingNewLiquidityHistory, &liquidity.LiquidityHistory{ - PairIndex: newLiquidity.PairIndex, - AssetAId: newLiquidity.AssetAId, - AssetA: newLiquidity.AssetA, - AssetBId: newLiquidity.AssetBId, - AssetB: newLiquidity.AssetB, - LpAmount: newLiquidity.LpAmount, - KLast: newLiquidity.KLast, - FeeRate: newLiquidity.FeeRate, - TreasuryAccountIndex: newLiquidity.TreasuryAccountIndex, - TreasuryRate: newLiquidity.TreasuryRate, - L2BlockHeight: blockHeight, - }) - } - - return pendingNewLiquidity, pendingUpdateLiquidity, pendingNewLiquidityHistory, nil -} - func (s *StateDB) GetPendingNft(blockHeight int64) ([]*nft.L2Nft, []*nft.L2Nft, []*nft.L2NftHistory, error) { pendingNewNft := make([]*nft.L2Nft, 0) pendingUpdateNft := make([]*nft.L2Nft, 0) @@ -513,7 +400,6 @@ func (s *StateDB) PrepareAccountsAndAssets(accountAssetsMap map[int64]map[int64] account.AssetInfo[assetId] = &types.AccountAsset{ AssetId: assetId, Balance: types.ZeroBigInt, - LpAmount: types.ZeroBigInt, OfferCanceledOrFinalized: types.ZeroBigInt, } } @@ -524,22 +410,6 @@ func (s *StateDB) PrepareAccountsAndAssets(accountAssetsMap map[int64]map[int64] return nil } -func (s *StateDB) PrepareLiquidity(pairIndex int64) error { - if s.dryRun { - l := &liquidity.Liquidity{} - redisLiquidity, err := s.redisCache.Get(context.Background(), dbcache.LiquidityKeyByIndex(pairIndex), l) - if err == nil && redisLiquidity != nil { - s.LiquidityCache.Add(pairIndex, l) - } - } - - _, err := s.GetLiquidity(pairIndex) - if err != nil { - return err - } - return nil -} - func (s *StateDB) PrepareNft(nftIndex int64) (*nft.L2Nft, error) { if s.dryRun { n := &nft.L2Nft{} @@ -568,16 +438,6 @@ func (s *StateDB) IntermediateRoot(cleanDirty bool) error { } } - for pairIndex, isDirty := range s.dirtyLiquidityMap { - if !isDirty { - continue - } - err := s.updateLiquidityTree(pairIndex) - if err != nil { - return err - } - } - for nftIndex, isDirty := range s.dirtyNftMap { if !isDirty { continue @@ -590,13 +450,11 @@ func (s *StateDB) IntermediateRoot(cleanDirty bool) error { if cleanDirty { s.dirtyAccountsAndAssetsMap = make(map[int64]map[int64]bool, 0) - s.dirtyLiquidityMap = make(map[int64]bool, 0) s.dirtyNftMap = make(map[int64]bool, 0) } hFunc := mimc.NewMiMC() hFunc.Write(s.AccountTree.Root()) - hFunc.Write(s.LiquidityTree.Root()) hFunc.Write(s.NftTree.Root()) s.StateRoot = common.Bytes2Hex(hFunc.Sum(nil)) return nil @@ -610,7 +468,6 @@ func (s *StateDB) updateAccountTree(accountIndex int64, assets []int64) error { for _, assetId := range assets { assetLeaf, err := tree.ComputeAccountAssetLeafHash( account.AssetInfo[assetId].Balance.String(), - account.AssetInfo[assetId].LpAmount.String(), account.AssetInfo[assetId].OfferCanceledOrFinalized.String(), ) if err != nil { @@ -641,33 +498,6 @@ func (s *StateDB) updateAccountTree(accountIndex int64, assets []int64) error { return nil } -func (s *StateDB) updateLiquidityTree(pairIndex int64) error { - liquidity, err := s.GetLiquidity(pairIndex) - if err != nil { - return err - } - nLiquidityAssetLeaf, err := tree.ComputeLiquidityAssetLeafHash( - liquidity.AssetAId, - liquidity.AssetA, - liquidity.AssetBId, - liquidity.AssetB, - liquidity.LpAmount, - liquidity.KLast, - liquidity.FeeRate, - liquidity.TreasuryAccountIndex, - liquidity.TreasuryRate, - ) - if err != nil { - return fmt.Errorf("unable to compute liquidity leaf: %v", err) - } - err = s.LiquidityTree.Set(uint64(pairIndex), nLiquidityAssetLeaf) - if err != nil { - return fmt.Errorf("unable to update liquidity tree: %v", err) - } - - return nil -} - func (s *StateDB) updateNftTree(nftIndex int64) error { nft, err := s.GetNft(nftIndex) if err != nil { diff --git a/dao/block/block.go b/dao/block/block.go index fa3d93c40..4b1cb5f34 100644 --- a/dao/block/block.go +++ b/dao/block/block.go @@ -24,7 +24,6 @@ import ( "github.com/bnb-chain/zkbnb/dao/account" "github.com/bnb-chain/zkbnb/dao/compressedblock" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/dao/tx" "github.com/bnb-chain/zkbnb/types" @@ -90,15 +89,12 @@ type ( Block *Block CompressedBlock *compressedblock.CompressedBlock - PendingNewAccount []*account.Account - PendingUpdateAccount []*account.Account - PendingNewAccountHistory []*account.AccountHistory - PendingNewLiquidity []*liquidity.Liquidity - PendingUpdateLiquidity []*liquidity.Liquidity - PendingNewLiquidityHistory []*liquidity.LiquidityHistory - PendingNewNft []*nft.L2Nft - PendingUpdateNft []*nft.L2Nft - PendingNewNftHistory []*nft.L2NftHistory + PendingNewAccount []*account.Account + PendingUpdateAccount []*account.Account + PendingNewAccountHistory []*account.AccountHistory + PendingNewNft []*nft.L2Nft + PendingUpdateNft []*nft.L2Nft + PendingNewNftHistory []*nft.L2NftHistory } ) diff --git a/dao/dbcache/cache.go b/dao/dbcache/cache.go index 4c96fa954..485b5184d 100644 --- a/dao/dbcache/cache.go +++ b/dao/dbcache/cache.go @@ -16,21 +16,16 @@ type Cache interface { } const ( - AccountKeyPrefix = "cache:account_" - LiquidityKeyPrefix = "cache:liquidity_" - NftKeyPrefix = "cache:nft_" - GasAccountKey = "cache:gasAccount" - GasConfigKey = "cache:gasConfig" + AccountKeyPrefix = "cache:account_" + NftKeyPrefix = "cache:nft_" + GasAccountKey = "cache:gasAccount" + GasConfigKey = "cache:gasConfig" ) func AccountKeyByIndex(accountIndex int64) string { return AccountKeyPrefix + fmt.Sprintf("%d", accountIndex) } -func LiquidityKeyByIndex(pairIndex int64) string { - return LiquidityKeyPrefix + fmt.Sprintf("%d", pairIndex) -} - func NftKeyByIndex(nftIndex int64) string { return NftKeyPrefix + fmt.Sprintf("%d", nftIndex) } diff --git a/dao/liquidity/liquidity.go b/dao/liquidity/liquidity.go deleted file mode 100644 index d6be00775..000000000 --- a/dao/liquidity/liquidity.go +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package liquidity - -import ( - "gorm.io/gorm" - - "github.com/bnb-chain/zkbnb/types" -) - -const ( - LiquidityTable = `liquidity` -) - -type ( - LiquidityModel interface { - CreateLiquidityTable() error - DropLiquidityTable() error - GetLiquidityByIndex(index int64) (entity *Liquidity, err error) - GetAllLiquidity() (liquidityList []*Liquidity, err error) - CreateLiquidityInTransact(tx *gorm.DB, liquidity []*Liquidity) error - UpdateLiquidityInTransact(tx *gorm.DB, liquidity []*Liquidity) error - } - - defaultLiquidityModel struct { - table string - DB *gorm.DB - } - - Liquidity struct { - gorm.Model - PairIndex int64 - AssetAId int64 - AssetA string - AssetBId int64 - AssetB string - LpAmount string - KLast string - FeeRate int64 - TreasuryAccountIndex int64 - TreasuryRate int64 - } -) - -func NewLiquidityModel(db *gorm.DB) LiquidityModel { - return &defaultLiquidityModel{ - table: LiquidityTable, - DB: db, - } -} - -func (*Liquidity) TableName() string { - return LiquidityTable -} - -func (m *defaultLiquidityModel) CreateLiquidityTable() error { - return m.DB.AutoMigrate(Liquidity{}) -} - -func (m *defaultLiquidityModel) DropLiquidityTable() error { - return m.DB.Migrator().DropTable(m.table) -} - -func (m *defaultLiquidityModel) GetLiquidityByIndex(pairIndex int64) (entity *Liquidity, err error) { - dbTx := m.DB.Table(m.table).Where("pair_index = ?", pairIndex).Find(&entity) - if dbTx.Error != nil { - return nil, types.DbErrSqlOperation - } else if dbTx.RowsAffected == 0 { - return nil, types.DbErrNotFound - } - return entity, nil -} - -func (m *defaultLiquidityModel) GetAllLiquidity() (liquidityList []*Liquidity, err error) { - dbTx := m.DB.Table(m.table).Order("id").Find(&liquidityList) - if dbTx.Error != nil { - return liquidityList, dbTx.Error - } else if dbTx.RowsAffected == 0 { - return nil, types.DbErrNotFound - } - return liquidityList, nil -} - -func (m *defaultLiquidityModel) CreateLiquidityInTransact(tx *gorm.DB, liquidity []*Liquidity) error { - dbTx := tx.Table(m.table).CreateInBatches(liquidity, len(liquidity)) - if dbTx.Error != nil { - return dbTx.Error - } - if dbTx.RowsAffected != int64(len(liquidity)) { - return types.DbErrFailToCreateLiquidity - } - return nil -} - -func (m *defaultLiquidityModel) UpdateLiquidityInTransact(tx *gorm.DB, liquidity []*Liquidity) error { - for _, pendingLiquidity := range liquidity { - dbTx := tx.Table(m.table).Where("pair_index = ?", pendingLiquidity.PairIndex). - Select("*"). - Updates(&pendingLiquidity) - if dbTx.Error != nil { - return dbTx.Error - } - if dbTx.RowsAffected == 0 { - return types.DbErrFailToUpdateLiquidity - } - } - return nil -} diff --git a/dao/liquidity/liquidity_history.go b/dao/liquidity/liquidity_history.go deleted file mode 100644 index 68314b749..000000000 --- a/dao/liquidity/liquidity_history.go +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package liquidity - -import ( - "gorm.io/gorm" - - "github.com/bnb-chain/zkbnb/types" -) - -const ( - LiquidityHistoryTable = `liquidity_history` -) - -type ( - LiquidityHistoryModel interface { - CreateLiquidityHistoryTable() error - DropLiquidityHistoryTable() error - GetLatestLiquidityByBlockHeight(blockHeight int64, limit int, offset int) (entities []*LiquidityHistory, err error) - GetLatestLiquidityCountByBlockHeight(blockHeight int64) (count int64, err error) - CreateLiquidityHistoriesInTransact(tx *gorm.DB, histories []*LiquidityHistory) error - } - - defaultLiquidityHistoryModel struct { - table string - DB *gorm.DB - } - - LiquidityHistory struct { - gorm.Model - PairIndex int64 - AssetAId int64 - AssetA string - AssetBId int64 - AssetB string - LpAmount string - KLast string - FeeRate int64 - TreasuryAccountIndex int64 - TreasuryRate int64 - L2BlockHeight int64 - } -) - -func NewLiquidityHistoryModel(db *gorm.DB) LiquidityHistoryModel { - return &defaultLiquidityHistoryModel{ - table: LiquidityHistoryTable, - DB: db, - } -} - -func (*LiquidityHistory) TableName() string { - return LiquidityHistoryTable -} - -func (m *defaultLiquidityHistoryModel) CreateLiquidityHistoryTable() error { - return m.DB.AutoMigrate(LiquidityHistory{}) -} - -func (m *defaultLiquidityHistoryModel) DropLiquidityHistoryTable() error { - return m.DB.Migrator().DropTable(m.table) -} - -func (m *defaultLiquidityHistoryModel) GetLatestLiquidityByBlockHeight(blockHeight int64, limit int, offset int) (entities []*LiquidityHistory, err error) { - subQuery := m.DB.Table(m.table).Select("*"). - Where("pair_index = a.pair_index AND l2_block_height <= ? AND l2_block_height > a.l2_block_height", blockHeight) - - dbTx := m.DB.Table(m.table+" as a").Select("*"). - Where("NOT EXISTS (?) AND l2_block_height <= ?", subQuery, blockHeight). - Limit(limit).Offset(offset). - Order("pair_index") - - if dbTx.Find(&entities).Error != nil { - return nil, types.DbErrSqlOperation - } else if dbTx.RowsAffected == 0 { - return nil, types.DbErrNotFound - } - return entities, nil -} - -func (m *defaultLiquidityHistoryModel) GetLatestLiquidityCountByBlockHeight(blockHeight int64) (count int64, err error) { - subQuery := m.DB.Table(m.table).Select("*"). - Where("pair_index = a.pair_index AND l2_block_height <= ? AND l2_block_height > a.l2_block_height", blockHeight) - - dbTx := m.DB.Table(m.table+" as a"). - Where("NOT EXISTS (?) AND l2_block_height <= ?", subQuery, blockHeight) - - if dbTx.Count(&count).Error != nil { - return 0, dbTx.Error - } - return count, nil -} - -func (m *defaultLiquidityHistoryModel) CreateLiquidityHistoriesInTransact(tx *gorm.DB, histories []*LiquidityHistory) error { - dbTx := tx.Table(m.table).CreateInBatches(histories, len(histories)) - if dbTx.Error != nil { - return dbTx.Error - } - if dbTx.RowsAffected != int64(len(histories)) { - return types.DbErrFailToCreateLiquidityHistory - } - return nil -} diff --git a/dao/tx/tx.go b/dao/tx/tx.go index f54f663ba..7be1ce3aa 100644 --- a/dao/tx/tx.go +++ b/dao/tx/tx.go @@ -71,7 +71,6 @@ type ( // Assigned after executed. GasFee string GasFeeAssetId int64 - PairIndex int64 NftIndex int64 CollectionId int64 AssetId int64 diff --git a/docs/api_reference.md b/docs/api_reference.md index 181155ccf..ecd4c0356 100644 --- a/docs/api_reference.md +++ b/docs/api_reference.md @@ -303,27 +303,6 @@ Get zkbnb general info, including contract address, and count of transactions an | ---- | ----------- | ------ | | 200 | A successful response. | [Layer2BasicInfo](#layer2basicinfo) | -### /api/v1/lpValue - -#### GET - -##### Summary - -Get liquidity pool amount for a specific liquidity pair - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ---- | -| pair_index | query | index of pair | Yes | integer | -| lp_amount | query | lp amount | Yes | string | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [LpValue](#lpvalue) | - ### /api/v1/maxOfferId #### GET @@ -385,40 +364,6 @@ Get next nonce | ---- | ----------- | ------ | | 200 | A successful response. | [NextNonce](#nextnonce) | -### /api/v1/pair - -#### GET - -##### Summary - -Get liquidity pool info by its index - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ---- | -| index | query | index of pair | Yes | integer | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [Pair](#pair) | - -### /api/v1/pairs - -#### GET - -##### Summary - -Get liquidity pairs - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [Pairs](#pairs) | - ### /api/v1/search #### GET @@ -439,29 +384,6 @@ Search with a specific keyword | ---- | ----------- | ------ | | 200 | A successful response. | [Search](#search) | -### /api/v1/swapAmount - -#### GET - -##### Summary - -Get swap amount for a specific liquidity pair and in asset amount - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ---- | -| pair_index | query | index of pair | Yes | integer | -| asset_id | query | id of asset | Yes | integer | -| asset_amount | query | amount of asset | Yes | string | -| is_from | query | is from asset | Yes | boolean (boolean) | - -##### Responses - -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | A successful response. | [SwapAmount](#swapamount) | - ### /api/v1/tx #### GET @@ -535,7 +457,6 @@ Send raw transaction | pk | string | | Yes | | nonce | long | | Yes | | assets | [ [AccountAsset](#accountasset) ] | | Yes | -| lps | [ [AccountLp](#accountlp) ] | | Yes | #### AccountAsset @@ -546,13 +467,6 @@ Send raw transaction | balance | string | | Yes | | price | string | | Yes | -#### AccountLp - -| Name | Type | Description | Required | -|--------| ---- | ----------- | -------- | -| index | integer | | Yes | -| amount | string | | Yes | - #### Accounts | Name | Type | Description | Required | @@ -658,19 +572,6 @@ Send raw transaction | today_active_user_count | long | | Yes | | contract_addresses | [ [ContractAddress](#contractaddress) ] | | Yes | -#### LpValue - -| Name | Type | Description | Required | -|----------------| ---- | ----------- | -------- | -| asset_a_id | integer | | Yes | -| asset_a_name | string | | Yes | -| asset_a_amount | string | | Yes | -| asset_a_price | string | | Yes | -| asset_b_id | integer | | Yes | -| asset_b_name | string | | Yes | -| asset_b_amount | string | | Yes | -| asset_b_price | string | | Yes | - #### MaxOfferId | Name | Type | Description | Required | @@ -703,29 +604,6 @@ Send raw transaction | total | long | | Yes | | nfts | [ [Nft](#nft) ] | | Yes | -#### Pair - -| Name | Type | Description | Required | -|-----------------| ---- | ----------- | -------- | -| index | integer | | Yes | -| asset_a_id | integer | | Yes | -| asset_a_name | string | | Yes | -| asset_a_amount | string | | Yes | -| asset_a_price | string | | Yes | -| asset_b_id | integer | | Yes | -| asset_b_name | string | | Yes | -| asset_b_amount | string | | Yes | -| asset_b_price | string | | Yes | -| fee_rate | long | | Yes | -| treasury_rate | long | | Yes | -| total_lp_amount | string | | Yes | - -#### Pairs - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| pairs | [ [Pair](#pair) ] | | Yes | - #### ReqGetAccount | Name | Type | Description | Required | @@ -786,13 +664,6 @@ Send raw transaction | asset_id | integer | | Yes | | tx_type | integer | | Yes | -#### ReqGetLpValue - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| pair_index | integer | | Yes | -| lp_amount | string | | Yes | - #### ReqGetMaxOfferId | Name | Type | Description | Required | @@ -805,12 +676,6 @@ Send raw transaction | ---- | ---- | ----------- | -------- | | account_index | integer | | Yes | -#### ReqGetPair - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| index | integer | | Yes | - #### ReqGetRange | Name | Type | Description | Required | @@ -818,15 +683,6 @@ Send raw transaction | offset | integer | | Yes | | limit | integer | | Yes | -#### ReqGetSwapAmount - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| pair_index | integer | | Yes | -| asset_id | integer | | Yes | -| asset_amount | string | | Yes | -| is_from | boolean (boolean) | | Yes | - #### ReqGetTx | Name | Type | Description | Required | @@ -867,14 +723,6 @@ Send raw transaction | status | integer | | Yes | | network_id | integer | | Yes | -#### SwapAmount - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| asset_id | integer | | Yes | -| asset_name | string | | Yes | -| asset_amount | string | | Yes | - #### Tx | Name | Type | Description | Required | @@ -888,7 +736,6 @@ Send raw transaction | gas_fee_asset_id | long | | Yes | | gas_fee | string | | Yes | | nft_index | long | | Yes | -| pair_index | long | | Yes | | asset_id | long | | Yes | | asset_name | string | | Yes | | native_adress | string | | Yes | diff --git a/docs/assets/storage_layout.png b/docs/assets/storage_layout.png index 6a2b62500ec65c19a814eb2051e120191fb620bb..9bafc96ae87ff51bef3f212c44033369c0ae3d3f 100644 GIT binary patch literal 42433 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�)u)OZEz@3yZowHxIjPVRh;$yse#y?OE~m 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 literal 63310 zcmbSz1yq!4+b%J5H_Fh`EeZ^s5`q#^(nG2AAOeE4(j_e*NGVc-K?u@~0tNyS5`!qx ziZq<(9o$?0|JZ=JPf#{ln>cV72(ztQ>^G$}|=lH%atP-ttZ8{*)=5I8t^vBZSn zC;OI0`rtpf-iDg0IF$qNuiy)bra5!+Z)m1L}Suf?1?3=b9 z9(^)Z9m^0NGkjBw(nuHPd3ITq-=#)tjMgjK^|tW5p$?BZSv{>t%~Gn$|M3^49LmYu40aBD|9Ls!C*b0U{_z+8?~7w*Lfn(~5EX0Q zM>+L;cx-(B^I%?H*5Q-F-%GH~ZfPZA7f#{3SmSnQIR$$ZMM)uE$#WjTd)eid^`~z? zBJ~w;Ie4vWJ7)0rQ8>f41Lw&VD4++FJL&R!Xe1-{x#4siV!uT%R30y|38`}|IqE!M ze}eT#R^3W%61W?vzeoB*OvKfJ6zV3?BanEQ`QJ-a{#zhyqkz0+atNS0U_JfXzi<2R zt8bwO7bBr!h>0Re$~fK(cKW|BIfN5j0Wz$phvt7Q^^faRgEi74Ov=sd9t9Lmu;|nPO8=y&>II5gupUK4WNBkBt49)a+2BTwPt&0PQs(B?caV&LJJ#M`OncOj?i&x$w6~4id^nt3s~aJu)2{I(>mK3 zJKrZ%mD#lKLr|@R9XteGK$>&xjZi96(`#j<>hTv9chsA9K4*tuw_WBq7OPEZ> zTQ8=U5`a<}b|tV1E#&&%pAMv=C+1##xpm*ttCImW7cXsy(eg(<4ftD#)3kwTJ9foe zLqZus1&!*-tBJmgFC;mjuw}_(oeCEA8M_wjE-xOOn;~k$v!)z zA%s|^4SfU?)WNivq`cgkvT&0#ZwjoZMcntBCD}xn1>PdCF>W0(p7LK{ZS`j}>-G9p zQQKGNHAl~$(;He!wkF3D}H_7`cVaMiYw{h`XR52t{>n;&}y>NI7I zX!y47(tzBmaH9N16g+UP)x}l%>Ud4X_2rK~!zbWCQH(51QT>N|t75(rUXil3g*s`1 z$#r(wI^l#A4xe9TEq;G4{O5Un26kP%`>sebWV${O`w5{=(L_DsBC0JtMZ@~>Z-><* z2)1kZ1c`f-#xJSj+57yqUBu9}YT1@wzITT9I7)rYwbhx0b1qhGQoNCo?$HVay?94&x$C3Wc@rwoG;o6z~lIOSRt%7Z?DXL#jf_Bje!h`nlp&^MscEJmF zF%~BmfK@PJA95C3Bw0Op|in;2IQd*l7HTX6Etmmas@P@G9wtF2l;-?`S&8%GQlnr z!_`KhqiOL5^T|_DPyY5Mq2)B5oT$cwpW|<ZV7;%{tisIlULjDG`*gb)(tONne|+vo7gSKvucO;C<_Dju0U^D>zQAxR7|S zC@xLpOd;p*b#dUb;z_aH>>pzVp6_z6N^&7w;P5`Q^H(%zi76wDI1_sf_S}9=XB!d{ zA8E~6YdJQ&{`y>Q`Q`|rS`CnE>cr#W8#C9g{W*L)%vJseBWk_$;r+W~Po4WgTu~X6 zn`+fw$0eQd{O}xMCuG&j!DN&M7&N1(lFUzS+mIJ+Xvu@ zVKF1vlh(zP>IwjnTzK1`VIJ%iEqZ+@d)2PYqyq9(ZwoaOjhl7aD$NboFZW*#o_jMp z47MXhJjxu&j~b1lA3yb5+-Re8Te{S$5+o~^7Pp-WFMQZ_3Fn0VAWE~POGZ7J+gjJ} z>~Axa6k-P*AU;#`-ilnQLE$--M7=SqYUFJ@t}fo|BVJ4-B@TiPjU2TAV8dlHo__QDoH`StEb)%`(#$9w7E@K&3TtXa?8Y^RX! ziRQa+Hsok@J;8s0v04>sl>BcwEBghGd&*_uD z=q`a$7jkM(pS*@AE;!~T*=q{!O?w$%F#>OP$~#{h2kVW!o~(TG^P@|Dri6WwRl^Oz zwyjUW&9Cy5Y?`)b$y!%e>KE8fAW%i*%;L(7V%EZZd4W$XeTIz}eS;5o9$E%0Ki}w} zyV%pk;vt-2eY5oXmmw8?lxGpJTUuneMsuPXl;J1rxcLbu?Tw)9i;%eP#h}&L*%0A( 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�!*od&Ppl-uz;9kp>?PnPXbuWN+|^rGd~nZb&sXqku#sIrOlMt zJaMN{M+Q=p@ing>8sn|J-RT3yVENE+I95KN6l|B{@a*iwmP65=pn_sFB|zJL_tEHGj&{CB3iHSWzZdDo zmvfRc;yi%#iQ*OvjZsfqikb6ld706`)V#<%g7bUafE-?Q5&+cGEbT5FYjsNR>>>`^ zvQAeUd4zU+hG2*F>^MY3AsUcBPvX8qC*E$k{Ix65eR)$GLsh5Z7XNWVPF$Exa1&K? zKQX4a)6ZqHHhI_RiG%|fot`%xtW2f!)|%$vhYjIuXE39)6g^~%Q0swbnh&@5(?n;` zw5-HBG{30UUrKZ6f3zE0eCqx5+#|@N(xb0LI(Wrc~!McE!7!vSK*~A75x3k*7d;?L33n{M8{KJ9*~6O2Bpt0U2Rtl>??8z9P^{yUL8C+? z+tWcc&%oa5_ad*?OukZR*2b4+&kC1u_yxSB66{~E3@FHJ*uYr*4WJ#Pn1H6igl5|yzVhg zAx8?&(Hh(jB*z5^-rlpDEI|MTGB#!Z_P6`yZ}-i=;J*1E5ft^`YySC9Mzh8JXD!2` zs(7!h8~z}EU<1$Cg=tYkJEl6^qSOrbu%MXKHDi3DCKOlpw2?Q|G}ze`XbpZvbjzh0 z!N!sGDU+P@D;%5!ExeVZzuXII$OEv*(n4k!%|n$NGxyA{zI&W8K=u2Mt^THohLu+4 zULQ_V{=RKT@Z2aVT;zb9|0asflr#cNdTs)A{bjT}I3qbz2i4?6{~&+AgHw)ESB`MY z-eDI!_K21j`-tmHEhPtFooGocr^UC7`E_d4_HuTPdk)F@ z%XxzoOV2_okJB%2)Fcbs~eR|Ot1U$Tr7aJuX4y~?@;U%8b!AqY%i$Vk9 zP$Zr+`DJ}D0)jx`ptO@W;6X*GK=F?f?sYLvhr$SIwti8EZe0P{Yx8bwjGz!aD)g0& zOV0m^8^}6E{bBKEh0ai+^NqK`P~io5>Ox5g-_HuKL50dqM^S~lphDVvX&V*l!~aIF zv1sn}+%9d|_`VRTDExGPJ5-?pqptG8)@*Hl{husDLrWqT72$s)D9X2K265Ku?1!|X*fP!+RaYgtIcC#-*nCD0mOencV6B=Hu$@B3j_zmw) zJ-3+qEE+$>*a3@OY3L4lez<}qeu~XW)Q}^z@Y6S<^&10&Wn>xmvroN3se=`=XC)3p zqo@xWotEnZu_++ZKkCr);T>q07bgFf?(ebtd)>kN_+R%{1k6MYOioUIU-q^6x%pDk zT&0vrc{9E2t7y-T4u*if&7)keoOQ~7?%eCUG^GygO*(|7qwAaE&n+R69}c}C(XfrJ zW$nXpI3I<-;o<+ji{d7O-B~2iPM!JoRaj#81r=|BD# DEx|89 diff --git a/docs/protocol.md b/docs/protocol.md index 19c7ded85..1cc152102 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -22,7 +22,6 @@ switch to EDCSA. ZkBNB implements a ZK rollup protocol (in short "rollup" below) for: - BNB and BEP20 fungible token deposit and transfer -- AMM-based fungible token swap on L2 - BEP721 non-fungible token deposit and transfer - mint BEP721 non-fungible tokens on L2 - NFT-marketplace on L2 @@ -30,7 +29,7 @@ ZkBNB implements a ZK rollup protocol (in short "rollup" below) for: General rollup workflow is as follows: - Users can become owners in rollup by calling registerZNS in L1 to register a short name for L2; -- Owners can transfer assets to each other, mint NFT on L2 or make a swap on L2; +- Owners can transfer assets to each other, mint NFT on L2; - Owners can withdraw assets under their control to any L1 address. Rollup operation requires the assistance of a committer, who rolls transactions together, also a prover who computes @@ -68,7 +67,7 @@ Mantissa and exponent parameters used in ZkBNB: ### State Merkle Tree(height) -We have 3 unique trees: `AccountTree(32)`, `LiquidityTree(16)`, `NftTree(40)` and one sub-tree `AssetTree(16)` which +We have 3 unique trees: `AccountTree(32)`, `NftTree(40)` and one sub-tree `AssetTree(16)` which belongs to `AccountTree(32)`. The empty leaf for all the trees is just set every attribute as `0` for every node. #### AccountTree @@ -115,12 +114,11 @@ func ComputeAccountLeafHash( ##### AssetTree -`AssetTree` is sub-tree of `AccountTree` and it stores all the assets `balance`, `lpAmount` and `offerCanceledOrFinalized`. The node of asset tree is: +`AssetTree` is sub-tree of `AccountTree` and it stores all the assets `balance`, and `offerCanceledOrFinalized`. The node of asset tree is: ```go type AssetNode struct { Balance string - LpAmount string OfferCanceledOrFinalized string // uint128 } ``` @@ -130,7 +128,6 @@ Leaf hash computation: ```go func ComputeAccountAssetLeafHash( balance string, - lpAmount string, offerCanceledOrFinalized string, ) (hashVal []byte, err error) { hFunc := mimc.NewMiMC() @@ -140,11 +137,6 @@ func ComputeAccountAssetLeafHash( logx.Errorf("[ComputeAccountAssetLeafHash] invalid balance: %s", err.Error()) return nil, err } - err = util.PaddingStringBigIntIntoBuf(&buf, lpAmount) - if err != nil { - logx.Errorf("[ComputeAccountAssetLeafHash] invalid balance: %s", err.Error()) - return nil, err - } err = util.PaddingStringBigIntIntoBuf(&buf, offerCanceledOrFinalized) if err != nil { logx.Errorf("[ComputeAccountAssetLeafHash] invalid balance: %s", err.Error()) @@ -155,73 +147,6 @@ func ComputeAccountAssetLeafHash( } ``` -#### LiquidityTree - -`LiquidityTree` is used for storing all the liquidity info and the node of the liquidity tree is: - -```go -type LiquidityNode struct { - AssetAId int64 - AssetA string - AssetBId int64 - AssetB string - LpAmount string - KLast string - FeeRate int64 - TreasuryAccountIndex int64 - TreasuryRate int64 -} -``` - -The liquidity pair is first initialized by `CreatePair` tx and will be changed by `UpdatePairRate`, `Swap`, `AddLiquidity` and `RemoveLiquidity` txs. - -Leaf hash computation: - -```go -func ComputeLiquidityAssetLeafHash( - assetAId int64, - assetA string, - assetBId int64, - assetB string, - lpAmount string, - kLast string, - feeRate int64, - treasuryAccountIndex int64, - treasuryRate int64, -) (hashVal []byte, err error) { - hFunc := mimc.NewMiMC() - var buf bytes.Buffer - util.PaddingInt64IntoBuf(&buf, assetAId) - err = util.PaddingStringBigIntIntoBuf(&buf, assetA) - if err != nil { - logx.Errorf("[ComputeLiquidityAssetLeafHash] unable to write big int to buf: %s", err.Error()) - return nil, err - } - util.PaddingInt64IntoBuf(&buf, assetBId) - err = util.PaddingStringBigIntIntoBuf(&buf, assetB) - if err != nil { - logx.Errorf("[ComputeLiquidityAssetLeafHash] unable to write big int to buf: %s", err.Error()) - return nil, err - } - err = util.PaddingStringBigIntIntoBuf(&buf, lpAmount) - if err != nil { - logx.Errorf("[ComputeLiquidityAssetLeafHash] unable to write big int to buf: %s", err.Error()) - return nil, err - } - err = util.PaddingStringBigIntIntoBuf(&buf, kLast) - if err != nil { - logx.Errorf("[ComputeLiquidityAssetLeafHash] unable to write big int to buf: %s", err.Error()) - return nil, err - } - util.PaddingInt64IntoBuf(&buf, feeRate) - util.PaddingInt64IntoBuf(&buf, treasuryAccountIndex) - util.PaddingInt64IntoBuf(&buf, treasuryRate) - hFunc.Write(buf.Bytes()) - hashVal = hFunc.Sum(nil) - return hashVal, nil -} -``` - #### NftTree `NftTree` is used for storing all the NFTs and the node info is: @@ -275,19 +200,17 @@ func ComputeNftAssetLeafHash( #### StateRoot -`StateRoot` is the final root that shows the final layer-2 state and will be stored on L1. It is computed by the root of `AccountTree`, `LiquidityTree` and `NftTree`. The computation of `StateRoot` works as follows: +`StateRoot` is the final root that shows the final layer-2 state and will be stored on L1. It is computed by the root of `AccountTree` and `NftTree`. The computation of `StateRoot` works as follows: -`StateRoot = MiMC(AccountRoot || LiquidityRoot || NftRoot)` +`StateRoot = MiMC(AccountRoot || NftRoot)` ```go func ComputeStateRootHash( accountRoot []byte, - liquidityRoot []byte, nftRoot []byte, ) []byte { hFunc := mimc.NewMiMC() hFunc.Write(accountRoot) - hFunc.Write(liquidityRoot) hFunc.Write(nftRoot) return hFunc.Sum(nil) } @@ -301,9 +224,6 @@ Rollup transactions: - EmptyTx - Transfer -- Swap -- AddLiquidity -- RemoveLiquidity - Withdraw - CreateCollection - MintNft @@ -315,8 +235,6 @@ Rollup transactions: Priority operations: - RegisterZNS -- CreatePair -- UpdatePairRate - Deposit - DepositNft - FullExit @@ -435,167 +353,6 @@ func VerifyRegisterZNSTx( } ``` -### CreatePair - -#### Description - -This is a layer-1 transaction and is used for creating a trading pair for L2. - -#### On-Chain operation - -##### Size - -| Chunks | Significant bytes | -| ------ | ----------------- | -| 6 | 15 | - -##### Structure - -| Name | Size(byte) | Comment | -| -------------------- | ---------- | ----------------------------- | -| TxType | 1 | transaction type | -| PairIndex | 2 | unique pair index | -| AssetAId | 2 | unique asset index | -| AssetBId | 2 | unique asset index | -| FeeRate | 2 | fee rate | -| TreasuryAccountIndex | 4 | unique treasury account index | -| TreasuryRate | 2 | treasury rate | - -```go -func ConvertTxToCreatePairPubData(oTx *tx.Tx) (pubData []byte, err error) { - if oTx.TxType != commonTx.TxTypeCreatePair { - logx.Errorf("[ConvertTxToCreatePairPubData] invalid tx type") - return nil, errors.New("[ConvertTxToCreatePairPubData] invalid tx type") - } - // parse tx - txInfo, err := commonTx.ParseCreatePairTxInfo(oTx.TxInfo) - if err != nil { - logx.Errorf("[ConvertTxToCreatePairPubData] unable to parse tx info: %s", err.Error()) - return nil, err - } - var buf bytes.Buffer - buf.WriteByte(uint8(oTx.TxType)) - buf.Write(Uint16ToBytes(uint16(txInfo.PairIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.AssetAId))) - buf.Write(Uint16ToBytes(uint16(txInfo.AssetBId))) - buf.Write(Uint16ToBytes(uint16(txInfo.FeeRate))) - buf.Write(Uint32ToBytes(uint32(txInfo.TreasuryAccountIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.TreasuryRate))) - chunk := SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - return buf.Bytes(), nil -} -``` - -#### User transaction - -| Name | Size(byte) | Comment | -| ------------- | ---------- | ----------------------- | -| AssetAAddress | 20 | asset a layer-1 address | -| AssetBAddress | 20 | asset b layer-1 address | - -#### Circuit - -```go -func VerifyCreatePairTx( - api API, flag Variable, - tx CreatePairTxConstraints, - liquidityBefore LiquidityConstraints, -) (pubData [PubDataSizePerTx]Variable) { - pubData = CollectPubDataFromCreatePair(api, tx) - // verify params - IsVariableEqual(api, flag, tx.PairIndex, liquidityBefore.PairIndex) - CheckEmptyLiquidityNode(api, flag, liquidityBefore) - return pubData -} -``` - -### UpdatePairRate - -#### Description - -This is a layer-1 transaction and is used for updating a trading pair for L2. - -#### On-Chain operation - -##### Size - -| Chunks | Significant bytes | -| ------ | ----------------- | -| 6 | 11 | - -##### Structure - -| Name | Size(byte) | Comment | -| -------------------- | ---------- | ----------------------------- | -| TxType | 1 | transaction type | -| PairIndex | 2 | unique pair index | -| FeeRate | 2 | fee rate | -| TreasuryAccountIndex | 4 | unique treasury account index | -| TreasuryRate | 2 | treasury rate | - -```go -func ConvertTxToUpdatePairRatePubData(oTx *tx.Tx) (pubData []byte, err error) { - if oTx.TxType != commonTx.TxTypeUpdatePairRate { - logx.Errorf("[ConvertTxToUpdatePairRatePubData] invalid tx type") - return nil, errors.New("[ConvertTxToUpdatePairRatePubData] invalid tx type") - } - // parse tx - txInfo, err := commonTx.ParseUpdatePairRateTxInfo(oTx.TxInfo) - if err != nil { - logx.Errorf("[ConvertTxToUpdatePairRatePubData] unable to parse tx info: %s", err.Error()) - return nil, err - } - var buf bytes.Buffer - buf.WriteByte(uint8(oTx.TxType)) - buf.Write(Uint16ToBytes(uint16(txInfo.PairIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.FeeRate))) - buf.Write(Uint32ToBytes(uint32(txInfo.TreasuryAccountIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.TreasuryRate))) - chunk := SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - return buf.Bytes(), nil -} -``` - -#### User transaction - -| Name | Size(byte) | Comment | -| -------------------- | ---------- | ----------------------- | -| AssetAAddress | 20 | asset a layer-1 address | -| AssetBAddress | 20 | asset b layer-1 address | -| FeeRate | 2 | fee rate | -| TreasuryAccountIndex | 4 | treasury account index | -| TreasuryRate | 2 | treasury rate | - -#### Circuit - -```go -func VerifyUpdatePairRateTx( - api API, flag Variable, - tx UpdatePairRateTxConstraints, - liquidityBefore LiquidityConstraints, -) (pubData [PubDataSizePerTx]Variable) { - pubData = CollectPubDataFromUpdatePairRate(api, tx) - // verify params - IsVariableEqual(api, flag, tx.PairIndex, liquidityBefore.PairIndex) - IsVariableLessOrEqual(api, flag, tx.TreasuryRate, tx.FeeRate) - return pubData -} -``` - ### Deposit #### Description @@ -901,519 +658,6 @@ func VerifyTransferTx( } ``` -### Swap - -#### Description - -This is a layer-2 transaction and is used for making a swap for assets in the layer-2 network. - -#### On-Chain operation - -##### Size - -| Chunks | Significant bytes | -| ------ | ----------------- | -| 6 | 25 | - -##### Structure - -| Name | Size(byte) | Comment | -| ------------------ | ---------- | --------------------- | -| TxType | 1 | transaction type | -| FromAccountIndex | 4 | from account index | -| PairIndex | 2 | unique pair index | -| AssetAAmount | 5 | packed asset amount | -| AssetBAmount | 5 | packed asset amount | -| GasFeeAccountIndex | 4 | gas fee account index | -| GasFeeAssetId | 2 | gas fee asset id | -| GasFeeAssetAmount | 2 | packed fee amount | - -```go -func ConvertTxToSwapPubData(oTx *tx.Tx) (pubData []byte, err error) { - if oTx.TxType != commonTx.TxTypeSwap { - logx.Errorf("[ConvertTxToSwapPubData] invalid tx type") - return nil, errors.New("[ConvertTxToSwapPubData] invalid tx type") - } - // parse tx - txInfo, err := commonTx.ParseSwapTxInfo(oTx.TxInfo) - if err != nil { - logx.Errorf("[ConvertTxToSwapPubData] unable to parse tx info: %s", err.Error()) - return nil, err - } - var buf bytes.Buffer - buf.WriteByte(uint8(oTx.TxType)) - buf.Write(Uint32ToBytes(uint32(txInfo.FromAccountIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.PairIndex))) - packedAssetAAmountBytes, err := AmountToPackedAmountBytes(txInfo.AssetAAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(packedAssetAAmountBytes) - packedAssetBAmountDeltaBytes, err := AmountToPackedAmountBytes(txInfo.AssetBAmountDelta) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(packedAssetBAmountDeltaBytes) - buf.Write(Uint32ToBytes(uint32(txInfo.GasAccountIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.GasFeeAssetId))) - packedFeeBytes, err := FeeToPackedFeeBytes(txInfo.GasFeeAssetAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed fee amount: %s", err.Error()) - return nil, err - } - buf.Write(packedFeeBytes) - chunk := SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - return buf.Bytes(), nil -} -``` - -#### User transaction - -```go -type SwapTxInfo struct { - FromAccountIndex int64 - PairIndex int64 - AssetAId int64 - AssetAAmount *big.Int - AssetBId int64 - AssetBMinAmount *big.Int - AssetBAmountDelta *big.Int - GasAccountIndex int64 - GasFeeAssetId int64 - GasFeeAssetAmount *big.Int - ExpiredAt int64 - Nonce int64 - Sig []byte -} -``` - -#### Circuit - -```go -func VerifySwapTx( - api API, flag Variable, - tx *SwapTxConstraints, - accountsBefore [NbAccountsPerTx]AccountConstraints, liquidityBefore LiquidityConstraints, -) (pubData [PubDataSizePerTx]Variable) { - pubData = CollectPubDataFromSwap(api, *tx) - // verify params - // account index - IsVariableEqual(api, flag, tx.FromAccountIndex, accountsBefore[0].AccountIndex) - IsVariableEqual(api, flag, tx.GasAccountIndex, accountsBefore[1].AccountIndex) - // pair index - IsVariableEqual(api, flag, tx.PairIndex, liquidityBefore.PairIndex) - // asset id - IsVariableEqual(api, flag, tx.AssetAId, accountsBefore[0].AssetsInfo[0].AssetId) - IsVariableEqual(api, flag, tx.AssetBId, accountsBefore[0].AssetsInfo[1].AssetId) - isSameAsset := api.IsZero( - api.And( - api.IsZero(api.Sub(tx.AssetAId, liquidityBefore.AssetAId)), - api.IsZero(api.Sub(tx.AssetBId, liquidityBefore.AssetBId)), - ), - ) - isDifferentAsset := api.IsZero( - api.And( - api.IsZero(api.Sub(tx.AssetAId, liquidityBefore.AssetBId)), - api.IsZero(api.Sub(tx.AssetBId, liquidityBefore.AssetAId)), - ), - ) - IsVariableEqual( - api, flag, - api.Or( - isSameAsset, - isDifferentAsset, - ), - 1, - ) - IsVariableEqual(api, flag, tx.GasFeeAssetId, accountsBefore[0].AssetsInfo[2].AssetId) - IsVariableEqual(api, flag, tx.GasFeeAssetId, accountsBefore[1].AssetsInfo[0].AssetId) - // should have enough assets - tx.AssetAAmount = UnpackAmount(api, tx.AssetAAmount) - tx.AssetBMinAmount = UnpackAmount(api, tx.AssetBMinAmount) - tx.AssetBAmountDelta = UnpackAmount(api, tx.AssetBAmountDelta) - tx.GasFeeAssetAmount = UnpackFee(api, tx.GasFeeAssetAmount) - IsVariableLessOrEqual(api, flag, tx.AssetBMinAmount, tx.AssetBAmountDelta) - IsVariableLessOrEqual(api, flag, tx.AssetAAmount, accountsBefore[0].AssetsInfo[0].Balance) - IsVariableLessOrEqual(api, flag, tx.GasFeeAssetAmount, accountsBefore[0].AssetsInfo[2].Balance) - // pool info - isSameAsset = api.And(flag, isSameAsset) - isDifferentAsset = api.And(flag, isSameAsset) - IsVariableEqual(api, flag, liquidityBefore.FeeRate, liquidityBefore.FeeRate) - IsVariableLessOrEqual(api, flag, liquidityBefore.FeeRate, RateBase) - assetAAmount := api.Select(isSameAsset, tx.AssetAAmount, tx.AssetBAmountDelta) - assetBAmount := api.Select(isSameAsset, tx.AssetBAmountDelta, tx.AssetAAmount) - // verify AMM - r := api.Mul(api.Mul(liquidityBefore.AssetA, liquidityBefore.AssetB), RateBase) - l := api.Mul( - api.Sub( - api.Mul(RateBase, api.Add(assetAAmount, liquidityBefore.AssetA)), - api.Mul(liquidityBefore.FeeRate, assetAAmount), - ), - api.Add(assetBAmount, liquidityBefore.AssetB), - ) - IsVariableLessOrEqual(api, flag, r, l) - return pubData -} -``` - -### AddLiquidity - -#### Description - -This is a layer-2 transaction and is used for adding liquidity for a trading pair in the layer-2 network. - -#### On-Chain operation - -##### Size - -| Chunks | Significant bytes | -| ------ | ----------------- | -| 6 | 40 | - -##### Structure - -| Name | Size(byte) | Comment | -| ------------------ | ---------- | ---------------------- | -| TxType | 1 | transaction type | -| FromAccountIndex | 4 | from account index | -| PairIndex | 2 | unique pair index | -| AssetAAmount | 5 | packed asset amount | -| AssetBAmount | 5 | packed asset amount | -| LpAmount | 5 | packed asset amount | -| KLast | 5 | packed k last amount | -| TreasuryAmount | 5 | packed treasury amount | -| GasFeeAccountIndex | 4 | gas fee account index | -| GasFeeAssetId | 2 | gas fee asset id | -| GasFeeAssetAmount | 2 | packed fee amount | - -```go -func ConvertTxToAddLiquidityPubData(oTx *tx.Tx) (pubData []byte, err error) { - if oTx.TxType != commonTx.TxTypeAddLiquidity { - logx.Errorf("[ConvertTxToAddLiquidityPubData] invalid tx type") - return nil, errors.New("[ConvertTxToAddLiquidityPubData] invalid tx type") - } - // parse tx - txInfo, err := commonTx.ParseAddLiquidityTxInfo(oTx.TxInfo) - if err != nil { - logx.Errorf("[ConvertTxToAddLiquidityPubData] unable to parse tx info: %s", err.Error()) - return nil, err - } - var buf bytes.Buffer - buf.WriteByte(uint8(oTx.TxType)) - buf.Write(Uint32ToBytes(uint32(txInfo.FromAccountIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.PairIndex))) - packedAssetAAmountBytes, err := AmountToPackedAmountBytes(txInfo.AssetAAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(packedAssetAAmountBytes) - packedAssetBAmountBytes, err := AmountToPackedAmountBytes(txInfo.AssetBAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(packedAssetBAmountBytes) - LpAmountBytes, err := AmountToPackedAmountBytes(txInfo.LpAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(LpAmountBytes) - KLastBytes, err := AmountToPackedAmountBytes(txInfo.KLast) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(KLastBytes) - chunk1 := SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - treasuryAmountBytes, err := AmountToPackedAmountBytes(txInfo.TreasuryAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(treasuryAmountBytes) - buf.Write(Uint32ToBytes(uint32(txInfo.GasAccountIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.GasFeeAssetId))) - packedFeeBytes, err := FeeToPackedFeeBytes(txInfo.GasFeeAssetAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed fee amount: %s", err.Error()) - return nil, err - } - buf.Write(packedFeeBytes) - chunk2 := PrefixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk1) - buf.Write(chunk2) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - return buf.Bytes(), nil -} -``` - -#### User transaction - -```go -type AddLiquidityTxInfo struct { - FromAccountIndex int64 - PairIndex int64 - AssetAId int64 - AssetAAmount *big.Int - AssetBId int64 - AssetBAmount *big.Int - LpAmount *big.Int - KLast *big.Int - TreasuryAmount *big.Int - GasAccountIndex int64 - GasFeeAssetId int64 - GasFeeAssetAmount *big.Int - ExpiredAt int64 - Nonce int64 - Sig []byte -} -``` - -#### Circuit - -```go -func VerifyAddLiquidityTx( - api API, flag Variable, - tx *AddLiquidityTxConstraints, - accountsBefore [NbAccountsPerTx]AccountConstraints, liquidityBefore LiquidityConstraints, - hFunc *MiMC, -) { - CollectPubDataFromAddLiquidity(api, flag, *tx, hFunc) - // check params - // account index - IsVariableEqual(api, flag, tx.FromAccountIndex, accountsBefore[0].AccountIndex) - IsVariableEqual(api, flag, liquidityBefore.TreasuryAccountIndex, accountsBefore[1].AccountIndex) - IsVariableEqual(api, flag, tx.GasAccountIndex, accountsBefore[2].AccountIndex) - // asset id - IsVariableEqual(api, flag, tx.AssetAId, accountsBefore[0].AssetsInfo[0].AssetId) - IsVariableEqual(api, flag, tx.AssetBId, accountsBefore[0].AssetsInfo[1].AssetId) - IsVariableEqual(api, flag, tx.AssetAId, liquidityBefore.AssetAId) - IsVariableEqual(api, flag, tx.AssetBId, liquidityBefore.AssetBId) - IsVariableEqual(api, flag, tx.PairIndex, accountsBefore[1].AssetsInfo[0].AssetId) - IsVariableEqual(api, flag, tx.GasFeeAssetId, accountsBefore[0].AssetsInfo[2].AssetId) - IsVariableEqual(api, flag, tx.GasFeeAssetId, accountsBefore[2].AssetsInfo[0].AssetId) - IsVariableLessOrEqual(api, flag, 0, tx.AssetAAmount) - IsVariableLessOrEqual(api, flag, 0, tx.AssetBAmount) - // check if the user has enough balance - tx.AssetAAmount = UnpackAmount(api, tx.AssetAAmount) - tx.AssetBAmount = UnpackAmount(api, tx.AssetBAmount) - tx.LpAmount = UnpackAmount(api, tx.LpAmount) - tx.GasFeeAssetAmount = UnpackFee(api, tx.GasFeeAssetAmount) - IsVariableLessOrEqual(api, flag, tx.AssetAAmount, accountsBefore[0].AssetsInfo[0].Balance) - IsVariableLessOrEqual(api, flag, tx.AssetBAmount, accountsBefore[0].AssetsInfo[1].Balance) - IsVariableLessOrEqual(api, flag, tx.GasFeeAssetAmount, accountsBefore[0].AssetsInfo[2].Balance) - IsVariableEqual(api, flag, tx.PoolAAmount, liquidityBefore.AssetA) - IsVariableEqual(api, flag, tx.PoolBAmount, liquidityBefore.AssetB) - // TODO verify ratio - l := api.Mul(liquidityBefore.AssetA, tx.AssetAAmount) - r := api.Mul(liquidityBefore.AssetB, tx.AssetBAmount) - maxDelta := std.Max(api, liquidityBefore.AssetA, liquidityBefore.AssetB) - l = std.Max(api, l, r) - r = std.Min(api, l, r) - lrDelta := api.Sub(l, r) - IsVariableLessOrEqual(api, flag, lrDelta, maxDelta) - // TODO verify lp amount - zeroFlag := api.Compiler().IsBoolean(api.Add(liquidityBefore.AssetA, 1)) - if zeroFlag { - // lpAmount = \sqrt{x * y} - lpAmountSquare := api.Mul(tx.AssetAAmount, tx.AssetBAmount) - IsVariableEqual(api, flag, api.Mul(tx.LpAmount, tx.LpAmount), lpAmountSquare) - } else { - // lpAmount = \Delta{x} / x * poolLp - IsVariableEqual(api, flag, api.Mul(tx.LpAmount, liquidityBefore.AssetA), api.Mul(tx.AssetAAmount, liquidityBefore.LpAmount)) - } -} -``` - -### RemoveLiquidity - -#### Description - -This is a layer-2 transaction and is used for removing liquidity for a trading pair in the layer-2 network. - -#### On-Chain operation - -##### Size - -| Chunks | Significant bytes | -| ------ | ----------------- | -| 6 | 40 | - -##### Structure - -| Name | Size(byte) | Comment | -| ------------------ | ---------- | ---------------------- | -| TxType | 1 | transaction type | -| FromAccountIndex | 4 | from account index | -| PairIndex | 2 | unique pair index | -| AssetAAmount | 5 | packed asset amount | -| AssetBAmount | 5 | packed asset amount | -| LpAmount | 5 | packed asset amount | -| KLast | 5 | packed k last amount | -| TreasuryAmount | 5 | packed treasury amount | -| GasFeeAccountIndex | 4 | gas fee account index | -| GasFeeAssetId | 2 | gas fee asset id | -| GasFeeAssetAmount | 2 | packed fee amount | - -```go -func ConvertTxToRemoveLiquidityPubData(oTx *tx.Tx) (pubData []byte, err error) { - if oTx.TxType != commonTx.TxTypeRemoveLiquidity { - logx.Errorf("[ConvertTxToRemoveLiquidityPubData] invalid tx type") - return nil, errors.New("[ConvertTxToRemoveLiquidityPubData] invalid tx type") - } - // parse tx - txInfo, err := commonTx.ParseRemoveLiquidityTxInfo(oTx.TxInfo) - if err != nil { - logx.Errorf("[ConvertTxToRemoveLiquidityPubData] unable to parse tx info: %s", err.Error()) - return nil, err - } - var buf bytes.Buffer - buf.WriteByte(uint8(oTx.TxType)) - buf.Write(Uint32ToBytes(uint32(txInfo.FromAccountIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.PairIndex))) - packedAssetAAmountBytes, err := AmountToPackedAmountBytes(txInfo.AssetAAmountDelta) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(packedAssetAAmountBytes) - packedAssetBAmountBytes, err := AmountToPackedAmountBytes(txInfo.AssetBAmountDelta) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(packedAssetBAmountBytes) - LpAmountBytes, err := AmountToPackedAmountBytes(txInfo.LpAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(LpAmountBytes) - KLastBytes, err := AmountToPackedAmountBytes(txInfo.KLast) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(KLastBytes) - chunk1 := SuffixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - treasuryAmountBytes, err := AmountToPackedAmountBytes(txInfo.TreasuryAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed amount: %s", err.Error()) - return nil, err - } - buf.Write(treasuryAmountBytes) - buf.Write(Uint32ToBytes(uint32(txInfo.GasAccountIndex))) - buf.Write(Uint16ToBytes(uint16(txInfo.GasFeeAssetId))) - packedFeeBytes, err := FeeToPackedFeeBytes(txInfo.GasFeeAssetAmount) - if err != nil { - logx.Errorf("[ConvertTxToDepositPubData] unable to convert amount to packed fee amount: %s", err.Error()) - return nil, err - } - buf.Write(packedFeeBytes) - chunk2 := PrefixPaddingBufToChunkSize(buf.Bytes()) - buf.Reset() - buf.Write(chunk1) - buf.Write(chunk2) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - buf.Write(PrefixPaddingBufToChunkSize([]byte{})) - return buf.Bytes(), nil -} -``` - -#### User transaction - -```go -type RemoveLiquidityTxInfo struct { - FromAccountIndex int64 - PairIndex int64 - AssetAId int64 - AssetAMinAmount *big.Int - AssetBId int64 - AssetBMinAmount *big.Int - LpAmount *big.Int - AssetAAmountDelta *big.Int - AssetBAmountDelta *big.Int - KLast *big.Int - TreasuryAmount *big.Int - GasAccountIndex int64 - GasFeeAssetId int64 - GasFeeAssetAmount *big.Int - ExpiredAt int64 - Nonce int64 - Sig []byte -} -``` - -#### Circuit - -```go -func VerifyRemoveLiquidityTx( - api API, flag Variable, - tx *RemoveLiquidityTxConstraints, - accountsBefore [NbAccountsPerTx]AccountConstraints, liquidityBefore LiquidityConstraints, -) (pubData [PubDataSizePerTx]Variable, err error) { - pubData = CollectPubDataFromRemoveLiquidity(api, *tx) - // verify params - // account index - IsVariableEqual(api, flag, tx.FromAccountIndex, accountsBefore[0].AccountIndex) - IsVariableEqual(api, flag, liquidityBefore.TreasuryAccountIndex, accountsBefore[1].AccountIndex) - IsVariableEqual(api, flag, tx.GasAccountIndex, accountsBefore[2].AccountIndex) - // asset id - IsVariableEqual(api, flag, tx.AssetAId, accountsBefore[0].AssetsInfo[0].AssetId) - IsVariableEqual(api, flag, tx.AssetBId, accountsBefore[0].AssetsInfo[1].AssetId) - IsVariableEqual(api, flag, tx.GasFeeAssetId, accountsBefore[0].AssetsInfo[2].AssetId) - IsVariableEqual(api, flag, tx.GasFeeAssetId, accountsBefore[2].AssetsInfo[0].AssetId) - IsVariableEqual(api, flag, tx.AssetAId, liquidityBefore.AssetAId) - IsVariableEqual(api, flag, tx.AssetBId, liquidityBefore.AssetBId) - // should have enough lp - IsVariableLessOrEqual(api, flag, tx.LpAmount, accountsBefore[0].AssetsInfo[3].LpAmount) - // enough balance - tx.AssetAMinAmount = UnpackAmount(api, tx.AssetAMinAmount) - tx.AssetAAmountDelta = UnpackAmount(api, tx.AssetAAmountDelta) - tx.AssetBMinAmount = UnpackAmount(api, tx.AssetBMinAmount) - tx.AssetBAmountDelta = UnpackAmount(api, tx.AssetBAmountDelta) - tx.LpAmount = UnpackAmount(api, tx.LpAmount) - tx.TreasuryAmount = UnpackAmount(api, tx.TreasuryAmount) - tx.GasFeeAssetAmount = UnpackFee(api, tx.GasFeeAssetAmount) - IsVariableLessOrEqual(api, flag, tx.GasFeeAssetAmount, accountsBefore[0].AssetsInfo[3].Balance) - // TODO verify LP - kCurrent := api.Mul(liquidityBefore.AssetA, liquidityBefore.AssetB) - IsVariableLessOrEqual(api, flag, liquidityBefore.KLast, kCurrent) - IsVariableLessOrEqual(api, flag, liquidityBefore.TreasuryRate, liquidityBefore.FeeRate) - sLps, err := api.Compiler().NewHint(ComputeSLp, 1, liquidityBefore.AssetA, liquidityBefore.AssetB, liquidityBefore.KLast, liquidityBefore.FeeRate, liquidityBefore.TreasuryRate) - if err != nil { - return pubData, err - } - sLp := sLps[0] - IsVariableEqual(api, flag, tx.TreasuryAmount, sLp) - poolLpVar := api.Sub(liquidityBefore.LpAmount, sLp) - IsVariableLessOrEqual(api, flag, api.Mul(tx.AssetAAmountDelta, poolLpVar), api.Mul(tx.LpAmount, liquidityBefore.AssetA)) - IsVariableLessOrEqual(api, flag, api.Mul(tx.AssetBAmountDelta, poolLpVar), api.Mul(tx.LpAmount, liquidityBefore.AssetB)) - IsVariableLessOrEqual(api, flag, tx.AssetAMinAmount, tx.AssetAAmountDelta) - IsVariableLessOrEqual(api, flag, tx.AssetBMinAmount, tx.AssetBAmountDelta) - return pubData, nil -} -``` - ### Withdraw #### Description @@ -2528,39 +1772,6 @@ function registerZNS(string calldata _name, address _owner, bytes32 _zkbnbPubKey - `_zkbnbPubKeyX`: ZkBNB layer-2 public key X - `_zkbnbPubKeyY`: ZkBNB layer-2 public key Y -#### CreatePair - -Create a trading pair for layer-2. - -```js -function createPair(address _tokenA, address _tokenB) external -``` - -- `_tokenA`: asset A address -- `_tokenB`: asset B address - -#### UpdatePairRate - -update a trading pair rate for layer-2: - -```js -struct PairInfo { - address tokenA; - address tokenB; - uint16 feeRate; - uint32 treasuryAccountIndex; - uint16 treasuryRate; -} - -function updatePairRate(PairInfo memory _pairInfo) external -``` - -- `_assetAAddr`: asset A address -- `_assetBAddr`: asset B address -- `_feeRate`: fee rate -- `_treasuryAccountIndex`: the treasury account index in the layer-2 network -- `_treasuryRate`: treasury rate - #### Deposit BNB Deposit BNB to Rollup - transfer BNB from user L1 address into Rollup account diff --git a/docs/readme.md b/docs/readme.md index 0fa5c6720..c792249ab 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -24,8 +24,6 @@ ZkBNB implement the following features so far: cryptographic. Users do not have to trust any third parties or keep monitoring the Rollup blocks in order to prevent fraud. - **L1<>L2 Communication**. BNB, and BEP20/BEP721/BEP1155 created on BSC or ZkBNB can flow freely between BSC and ZkBNB. -- **Built-in instant AMM swap**. It allows digital assets to be traded without permission and automatically by using - liquidity pools. - **Built-in NFT marketplace**. Developer can build marketplace for crypto collectibles and non-fungible tokens (NFTs) out of box on ZkBNB. - **Fast transaction speed and faster finality**. diff --git a/docs/storage_layout.md b/docs/storage_layout.md index 1800425ea..ce97cf5ba 100644 --- a/docs/storage_layout.md +++ b/docs/storage_layout.md @@ -10,8 +10,6 @@ - `L1 Synced Block`: record block information from L1 - `Compressed Block`: record other information of L2 block - `Block`: record L2 block information - - `Liquidity`: record Liquidity related information - - `Liquidity History`: record the historical change information of Liquidity - `Pool Tx`: record pending and executed but not packed Tx messages - `L2 NFT`: record NFT related information - `L2 NFT History`: record the historical status change information of NFT @@ -27,7 +25,6 @@ There are 4 types of trees in the system. - Account Tree - Account Asset Tree - - Liquidity Tree - Nft Tree ## Account Tree @@ -37,10 +34,6 @@ Used to record and save account status under each block height. ## Account Asset Tree Each Account will maintain an Asset tree, the `Balance`, `LpAmount`, and `OfferCanceledOrFinalized` of each Asset will be calculated as a hash and written into the tree corresponding to the `AssetID`. -## Liquidity Tree -The `AssetAId`, `AssetA`, `AssetBId`, `AssetB`, `LpAmount`, `KLast`, `FeeRate`, `TreasuryAccountIndex`, and `TreasuryRate` of each liquidity resource will be calculated as a hash and written into the tree corresponding to the `PairIndex`. -Used to record and save liquidity status under each block height. - ## Nft Tree The `CreatorAccountIndex`, `OwnerAccountIndex`, `NftContentHash`, `NftL1Address`, `NftL1TokenId`, `CreatorTreasuryRate`, and `CollectionId` of each nft resource will be calculated as a hash and written into the tree corresponding to the `NftIndex`. Used to record and save nft status under each block height. diff --git a/docs/technology.md b/docs/technology.md index 0d1bfe286..5f4bbb891 100644 --- a/docs/technology.md +++ b/docs/technology.md @@ -8,7 +8,7 @@ - **prover**. Prover generates cryptographic proof based on the witness materials. - **sender**. The sender rollups the compressed l2 blocks to L1, and submit proof to verify it. - **api server**. The api server is the access endpoints for most users, it provides rich data, including - digital assets, blocks, transactions, swap info, gas fees. + digital assets, blocks, transactions, gas fees. - **recovery**. A tool to recover the sparse merkle tree in kv-rocks based on the state world in postgresql. ## Maximum throughput diff --git a/docs/wallets.md b/docs/wallets.md index 8f0227a05..58d55f11f 100644 --- a/docs/wallets.md +++ b/docs/wallets.md @@ -180,52 +180,6 @@ Below is the typescript definition of transaction and EIP712Domain. These typed { name: 'Nonce', type: 'uint256' }, { name: 'ChainId', type: 'uint256' }, ], -``` -##### AddLiquidity -```typescript= - AddLiquidity: [ - { name: 'FromAccountIndex', type: 'uint256' }, - { name: 'PairIndex', type: 'uint256' }, - { name: 'AssetAAmount', type: 'uint256' }, - { name: 'AssetBAmount', type: 'uint256' }, - { name: 'GasAccountIndex', type: 'uint256' }, - { name: 'GasFeeAssetId', type: 'uint256' }, - { name: 'GasFeeAssetAmount', type: 'uint256' }, - { name: 'ExpiredAt', type: 'uint256' }, - { name: 'Nonce', type: 'uint256' }, - { name: 'ChainId', type: 'uint256' }, - ], -``` -##### RemoveLiquidity -```typescript= - RemoveLiquidity: [ - { name: 'FromAccountIndex', type: 'uint256' }, - { name: 'PairIndex', type: 'uint256' }, - { name: 'AssetAMinAmount', type: 'uint256' }, - { name: 'AssetBMinAmount', type: 'uint256' }, - { name: 'LpAmount', type: 'uint256' }, - { name: 'GasAccountIndex', type: 'uint256' }, - { name: 'GasFeeAssetId', type: 'uint256' }, - { name: 'GasFeeAssetAmount', type: 'uint256' }, - { name: 'ExpiredAt', type: 'uint256' }, - { name: 'Nonce', type: 'uint256' }, - { name: 'ChainId', type: 'uint256' }, - ], -``` -##### Swap -```typescript= - Swap: [ - { name: 'FromAccountIndex', type: 'uint256' }, - { name: 'PairIndex', type: 'uint256' }, - { name: 'AssetAAmount', type: 'uint256' }, - { name: 'AssetBMinAmount', type: 'uint256' }, - { name: 'GasAccountIndex', type: 'uint256' }, - { name: 'GasFeeAssetId', type: 'uint256' }, - { name: 'GasFeeAssetAmount', type: 'uint256' }, - { name: 'ExpiredAt', type: 'uint256' }, - { name: 'Nonce', type: 'uint256' }, - { name: 'ChainId', type: 'uint256' }, - ], ``` ##### CreateCollection ```typescript= diff --git a/go.mod b/go.mod index cb1b08d48..2c0f42c48 100644 --- a/go.mod +++ b/go.mod @@ -87,7 +87,7 @@ require ( ) require ( - github.com/bnb-chain/zkbnb-crypto v0.0.6 + github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220928090246-9a20106a2347 github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f github.com/consensys/gnark v0.7.0 @@ -104,7 +104,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.2 // indirect golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect + golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6 // indirect google.golang.org/grpc v1.46.2 // indirect google.golang.org/protobuf v1.28.0 // indirect gorm.io/driver/postgres v1.3.6 diff --git a/go.sum b/go.sum index 274d33d5e..8652cbe7e 100644 --- a/go.sum +++ b/go.sum @@ -117,12 +117,10 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/bnb-chain/zkbnb-crypto v0.0.6 h1:UbD9XzTNQXfcEfI35MHbMMZ5IgqQFidYtvamAbHfS3o= -github.com/bnb-chain/zkbnb-crypto v0.0.6/go.mod h1:SrKwMMrqi1Bxco6IYGXmqo7PvKVn3T3TuMMc7jD4LOA= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220928090246-9a20106a2347 h1:Dv+ztM5Bb8I2m3cf5WDYZZ+sFmNhWzNS41cxAx2AUrc= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220928090246-9a20106a2347/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 h1:1rMa8XpplDNZaxeM1ifXMjSSeH/ucJyLUjHHEw1z4AA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2/go.mod h1:T69T8enicQ5kSRPIzyPJv/jhuvRMz1UxsijPXmlis+I= -github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220907130044-9c7cccbd19fa h1:aVqkz6Ge3eW7SKmINYMprpxq2VNpKp4vKQ6dEue8uUE= -github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220907130044-9c7cccbd19fa/go.mod h1:mGIAve72dt/VOVQ2wu7UjcjnMspnKczi5QACE1NGVec= github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f h1:zBVWOWlH4w18O6wp0gZML4U2n1rxsFLb7KB7DFE8zcQ= github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f/go.mod h1:mGIAve72dt/VOVQ2wu7UjcjnMspnKczi5QACE1NGVec= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= @@ -1199,8 +1197,9 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6 h1:cy1ko5847T/lJ45eyg/7uLprIE/amW5IXxGtEnQdYMI= +golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/service/apiserver/internal/fetcher/state/fetcher.go b/service/apiserver/internal/fetcher/state/fetcher.go index bf12aa45b..e5860c32e 100644 --- a/service/apiserver/internal/fetcher/state/fetcher.go +++ b/service/apiserver/internal/fetcher/state/fetcher.go @@ -6,38 +6,33 @@ import ( "github.com/bnb-chain/zkbnb/common/chain" accdao "github.com/bnb-chain/zkbnb/dao/account" "github.com/bnb-chain/zkbnb/dao/dbcache" - liqdao "github.com/bnb-chain/zkbnb/dao/liquidity" nftdao "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/types" ) //go:generate mockgen -source api.go -destination api_mock.go -package state -// Fetcher will fetch the latest states (account,nft,liquidity) from redis, which is written by committer; +// Fetcher will fetch the latest states (account,nft) from redis, which is written by committer; // and if the required data cannot be found then database will be used. type Fetcher interface { GetLatestAccount(accountIndex int64) (accountInfo *types.AccountInfo, err error) - GetLatestLiquidity(pairIndex int64) (liquidityInfo *types.LiquidityInfo, err error) GetLatestNft(nftIndex int64) (*types.NftInfo, error) } func NewFetcher(redisCache dbcache.Cache, accountModel accdao.AccountModel, - liquidityModel liqdao.LiquidityModel, nftModel nftdao.L2NftModel) Fetcher { return &fetcher{ - redisCache: redisCache, - accountModel: accountModel, - liquidityModel: liquidityModel, - nftModel: nftModel, + redisCache: redisCache, + accountModel: accountModel, + nftModel: nftModel, } } type fetcher struct { - redisCache dbcache.Cache - accountModel accdao.AccountModel - liquidityModel liqdao.LiquidityModel - nftModel nftdao.L2NftModel + redisCache dbcache.Cache + accountModel accdao.AccountModel + nftModel nftdao.L2NftModel } func (f *fetcher) GetLatestAccount(accountIndex int64) (*types.AccountInfo, error) { @@ -63,32 +58,6 @@ func (f *fetcher) GetLatestAccount(accountIndex int64) (*types.AccountInfo, erro return fa, nil } -func (f *fetcher) GetLatestLiquidity(pairIndex int64) (liquidityInfo *types.LiquidityInfo, err error) { - l := &liqdao.Liquidity{} - - redisLiquidity, err := f.redisCache.Get(context.Background(), dbcache.LiquidityKeyByIndex(pairIndex), l) - if err == nil && redisLiquidity != "" { - } else { - l, err = f.liquidityModel.GetLiquidityByIndex(pairIndex) - if err != nil { - return nil, err - } - } - - return types.ConstructLiquidityInfo( - pairIndex, - l.AssetAId, - l.AssetA, - l.AssetBId, - l.AssetB, - l.LpAmount, - l.KLast, - l.FeeRate, - l.TreasuryAccountIndex, - l.TreasuryRate, - ) -} - func (f *fetcher) GetLatestNft(nftIndex int64) (*types.NftInfo, error) { n := &nftdao.L2Nft{} diff --git a/service/apiserver/internal/handler/pair/getlpvaluehandler.go b/service/apiserver/internal/handler/pair/getlpvaluehandler.go deleted file mode 100644 index dee9be1cd..000000000 --- a/service/apiserver/internal/handler/pair/getlpvaluehandler.go +++ /dev/null @@ -1,29 +0,0 @@ -package pair - -import ( - "net/http" - - "github.com/zeromicro/go-zero/rest/httpx" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/logic/pair" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/svc" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" -) - -func GetLpValueHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req types.ReqGetLpValue - if err := httpx.Parse(r, &req); err != nil { - httpx.Error(w, err) - return - } - - l := pair.NewGetLpValueLogic(r.Context(), svcCtx) - resp, err := l.GetLPValue(&req) - if err != nil { - httpx.Error(w, err) - } else { - httpx.OkJson(w, resp) - } - } -} diff --git a/service/apiserver/internal/handler/pair/getpairhandler.go b/service/apiserver/internal/handler/pair/getpairhandler.go deleted file mode 100644 index 260654145..000000000 --- a/service/apiserver/internal/handler/pair/getpairhandler.go +++ /dev/null @@ -1,29 +0,0 @@ -package pair - -import ( - "net/http" - - "github.com/zeromicro/go-zero/rest/httpx" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/logic/pair" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/svc" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" -) - -func GetPairHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req types.ReqGetPair - if err := httpx.Parse(r, &req); err != nil { - httpx.Error(w, err) - return - } - - l := pair.NewGetPairLogic(r.Context(), svcCtx) - resp, err := l.GetPair(&req) - if err != nil { - httpx.Error(w, err) - } else { - httpx.OkJson(w, resp) - } - } -} diff --git a/service/apiserver/internal/handler/pair/getpairshandler.go b/service/apiserver/internal/handler/pair/getpairshandler.go deleted file mode 100644 index d158ce98b..000000000 --- a/service/apiserver/internal/handler/pair/getpairshandler.go +++ /dev/null @@ -1,22 +0,0 @@ -package pair - -import ( - "net/http" - - "github.com/zeromicro/go-zero/rest/httpx" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/logic/pair" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/svc" -) - -func GetPairsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - l := pair.NewGetPairsLogic(r.Context(), svcCtx) - resp, err := l.GetPairs() - if err != nil { - httpx.Error(w, err) - } else { - httpx.OkJson(w, resp) - } - } -} diff --git a/service/apiserver/internal/handler/pair/getswapamounthandler.go b/service/apiserver/internal/handler/pair/getswapamounthandler.go deleted file mode 100644 index cab782d9a..000000000 --- a/service/apiserver/internal/handler/pair/getswapamounthandler.go +++ /dev/null @@ -1,29 +0,0 @@ -package pair - -import ( - "net/http" - - "github.com/zeromicro/go-zero/rest/httpx" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/logic/pair" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/svc" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" -) - -func GetSwapAmountHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req types.ReqGetSwapAmount - if err := httpx.Parse(r, &req); err != nil { - httpx.Error(w, err) - return - } - - l := pair.NewGetSwapAmountLogic(r.Context(), svcCtx) - resp, err := l.GetSwapAmount(&req) - if err != nil { - httpx.Error(w, err) - } else { - httpx.OkJson(w, resp) - } - } -} diff --git a/service/apiserver/internal/handler/routes.go b/service/apiserver/internal/handler/routes.go index 64bc7050f..393256772 100644 --- a/service/apiserver/internal/handler/routes.go +++ b/service/apiserver/internal/handler/routes.go @@ -9,7 +9,6 @@ import ( block "github.com/bnb-chain/zkbnb/service/apiserver/internal/handler/block" info "github.com/bnb-chain/zkbnb/service/apiserver/internal/handler/info" nft "github.com/bnb-chain/zkbnb/service/apiserver/internal/handler/nft" - pair "github.com/bnb-chain/zkbnb/service/apiserver/internal/handler/pair" root "github.com/bnb-chain/zkbnb/service/apiserver/internal/handler/root" transaction "github.com/bnb-chain/zkbnb/service/apiserver/internal/handler/transaction" "github.com/bnb-chain/zkbnb/service/apiserver/internal/svc" @@ -108,31 +107,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { }, ) - server.AddRoutes( - []rest.Route{ - { - Method: http.MethodGet, - Path: "/api/v1/swapAmount", - Handler: pair.GetSwapAmountHandler(serverCtx), - }, - { - Method: http.MethodGet, - Path: "/api/v1/pairs", - Handler: pair.GetPairsHandler(serverCtx), - }, - { - Method: http.MethodGet, - Path: "/api/v1/lpValue", - Handler: pair.GetLpValueHandler(serverCtx), - }, - { - Method: http.MethodGet, - Path: "/api/v1/pair", - Handler: pair.GetPairHandler(serverCtx), - }, - }, - ) - server.AddRoutes( []rest.Route{ { diff --git a/service/apiserver/internal/logic/account/getaccountlogic.go b/service/apiserver/internal/logic/account/getaccountlogic.go index 7b373b7d4..0b2e0e89a 100644 --- a/service/apiserver/internal/logic/account/getaccountlogic.go +++ b/service/apiserver/internal/logic/account/getaccountlogic.go @@ -75,14 +75,12 @@ func (l *GetAccountLogic) GetAccount(req *types.ReqGetAccount) (resp *types.Acco Pk: account.PublicKey, Nonce: account.Nonce, Assets: make([]*types.AccountAsset, 0, len(account.AssetInfo)), - Lps: make([]*types.AccountLp, 0, len(account.AssetInfo)), } for _, asset := range account.AssetInfo { if asset.AssetId > maxAssetId { continue //it is used for offer related, or empty balance; max ip id should be less than max asset id } - if (asset.Balance == nil || asset.Balance.Cmp(types2.ZeroBigInt) == 0) && - (asset.LpAmount == nil || asset.LpAmount.Cmp(types2.ZeroBigInt) == 0) { + if asset.Balance == nil || asset.Balance.Cmp(types2.ZeroBigInt) == 0 { continue } if asset.Balance != nil && asset.Balance.Cmp(types2.ZeroBigInt) > 0 { @@ -107,12 +105,6 @@ func (l *GetAccountLogic) GetAccount(req *types.ReqGetAccount) (resp *types.Acco Price: strconv.FormatFloat(assetPrice, 'E', -1, 64), }) } - if asset.LpAmount != nil && asset.LpAmount.Cmp(types2.ZeroBigInt) > 0 { - resp.Lps = append(resp.Lps, &types.AccountLp{ - Index: uint32(asset.AssetId), - Amount: asset.LpAmount.String(), - }) - } } sort.Slice(resp.Assets, func(i, j int) bool { diff --git a/service/apiserver/internal/logic/pair/getlpvaluelogic.go b/service/apiserver/internal/logic/pair/getlpvaluelogic.go deleted file mode 100644 index 8586e41c1..000000000 --- a/service/apiserver/internal/logic/pair/getlpvaluelogic.go +++ /dev/null @@ -1,80 +0,0 @@ -package pair - -import ( - "context" - "math/big" - "strconv" - - "github.com/zeromicro/go-zero/core/logx" - - "github.com/bnb-chain/zkbnb/common/chain" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/svc" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" - types2 "github.com/bnb-chain/zkbnb/types" -) - -type GetLpValueLogic struct { - logx.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewGetLpValueLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLpValueLogic { - return &GetLpValueLogic{ - Logger: logx.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetLpValueLogic) GetLPValue(req *types.ReqGetLpValue) (resp *types.LpValue, err error) { - amount, isTure := new(big.Int).SetString(req.LpAmount, 10) - if !isTure { - logx.Errorf("fail to convert string: %s to int", req.LpAmount) - return nil, types2.AppErrInvalidParam.RefineError("invalid LpAmount") - } - - liquidity, err := l.svcCtx.StateFetcher.GetLatestLiquidity(int64(req.PairIndex)) - if err != nil { - if err == types2.DbErrNotFound { - return nil, types2.AppErrNotFound - } - return nil, types2.AppErrInternal - } - assetAAmount, assetBAmount := big.NewInt(0), big.NewInt(0) - if liquidity.LpAmount.Cmp(types2.ZeroBigInt) > 0 { - assetAAmount, assetBAmount, err = chain.ComputeRemoveLiquidityAmount(liquidity, amount) - if err != nil { - logx.Errorf("fail to compute liquidity amount, err: %s", err.Error()) - return nil, types2.AppErrInternal - } - } - assetA, err := l.svcCtx.AssetModel.GetAssetById(liquidity.AssetAId) - if err != nil { - return nil, types2.AppErrInternal - } - assetB, err := l.svcCtx.AssetModel.GetAssetById(liquidity.AssetBId) - if err != nil { - return nil, types2.AppErrInternal - } - assetAPrice, err := l.svcCtx.PriceFetcher.GetCurrencyPrice(l.ctx, assetA.AssetSymbol) - if err != nil { - return nil, types2.AppErrInternal - } - assetBPrice, err := l.svcCtx.PriceFetcher.GetCurrencyPrice(l.ctx, assetB.AssetSymbol) - if err != nil { - return nil, types2.AppErrInternal - } - resp = &types.LpValue{ - AssetAId: uint32(liquidity.AssetAId), - AssetAName: assetA.AssetName, - AssetAAmount: assetAAmount.String(), - AssetAPrice: strconv.FormatFloat(assetAPrice, 'E', -1, 64), - AssetBId: uint32(liquidity.AssetBId), - AssetBName: assetB.AssetName, - AssetBAmount: assetBAmount.String(), - AssetBPrice: strconv.FormatFloat(assetBPrice, 'E', -1, 64), - } - - return resp, nil -} diff --git a/service/apiserver/internal/logic/pair/getpairlogic.go b/service/apiserver/internal/logic/pair/getpairlogic.go deleted file mode 100644 index b9fafe4d6..000000000 --- a/service/apiserver/internal/logic/pair/getpairlogic.go +++ /dev/null @@ -1,66 +0,0 @@ -package pair - -import ( - "context" - "strconv" - - "github.com/zeromicro/go-zero/core/logx" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/svc" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" - types2 "github.com/bnb-chain/zkbnb/types" -) - -type GetPairLogic struct { - logx.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewGetPairLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPairLogic { - return &GetPairLogic{ - Logger: logx.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetPairLogic) GetPair(req *types.ReqGetPair) (resp *types.Pair, err error) { - liquidity, err := l.svcCtx.StateFetcher.GetLatestLiquidity(int64(req.Index)) - if err != nil { - logx.Errorf("fail to get pair info: %d, err: %s", req.Index, err.Error()) - if err == types2.DbErrNotFound { - return nil, types2.AppErrNotFound - } - return nil, types2.AppErrInternal - } - assetA, err := l.svcCtx.AssetModel.GetAssetById(liquidity.AssetAId) - if err != nil { - return nil, types2.AppErrInternal - } - assetB, err := l.svcCtx.AssetModel.GetAssetById(liquidity.AssetBId) - if err != nil { - return nil, types2.AppErrInternal - } - assetAPrice, err := l.svcCtx.PriceFetcher.GetCurrencyPrice(l.ctx, assetA.AssetSymbol) - if err != nil { - return nil, types2.AppErrInternal - } - assetBPrice, err := l.svcCtx.PriceFetcher.GetCurrencyPrice(l.ctx, assetB.AssetSymbol) - if err != nil { - return nil, types2.AppErrInternal - } - resp = &types.Pair{ - Index: uint32(liquidity.PairIndex), - AssetAId: uint32(liquidity.AssetAId), - AssetAName: assetA.AssetName, - AssetAAmount: liquidity.AssetA.String(), - AssetAPrice: strconv.FormatFloat(assetAPrice, 'E', -1, 64), - AssetBId: uint32(liquidity.AssetBId), - AssetBName: assetB.AssetName, - AssetBAmount: liquidity.AssetB.String(), - AssetBPrice: strconv.FormatFloat(assetBPrice, 'E', -1, 64), - TotalLpAmount: liquidity.LpAmount.String(), - } - return resp, nil -} diff --git a/service/apiserver/internal/logic/pair/getpairslogic.go b/service/apiserver/internal/logic/pair/getpairslogic.go deleted file mode 100644 index 6d75c5152..000000000 --- a/service/apiserver/internal/logic/pair/getpairslogic.go +++ /dev/null @@ -1,72 +0,0 @@ -package pair - -import ( - "context" - "strconv" - - "github.com/zeromicro/go-zero/core/logx" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/svc" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" - types2 "github.com/bnb-chain/zkbnb/types" -) - -type GetPairsLogic struct { - logx.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewGetPairsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPairsLogic { - return &GetPairsLogic{ - Logger: logx.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetPairsLogic) GetPairs() (*types.Pairs, error) { - resp := &types.Pairs{Pairs: make([]*types.Pair, 0)} - - liquidityAssets, err := l.svcCtx.LiquidityModel.GetAllLiquidity() - if err != nil { - if err == types2.DbErrNotFound { - return resp, nil - } - return nil, types2.AppErrInternal - } - - for _, liquidity := range liquidityAssets { - assetA, err := l.svcCtx.AssetModel.GetAssetById(liquidity.AssetAId) - if err != nil { - return nil, types2.AppErrInternal - } - assetB, err := l.svcCtx.AssetModel.GetAssetById(liquidity.AssetBId) - if err != nil { - return nil, types2.AppErrInternal - } - assetAPrice, err := l.svcCtx.PriceFetcher.GetCurrencyPrice(l.ctx, assetA.AssetSymbol) - if err != nil { - return nil, types2.AppErrInternal - } - assetBPrice, err := l.svcCtx.PriceFetcher.GetCurrencyPrice(l.ctx, assetB.AssetSymbol) - if err != nil { - return nil, types2.AppErrInternal - } - resp.Pairs = append(resp.Pairs, &types.Pair{ - Index: uint32(liquidity.PairIndex), - AssetAId: uint32(liquidity.AssetAId), - AssetAName: assetA.AssetName, - AssetAAmount: liquidity.AssetA, - AssetAPrice: strconv.FormatFloat(assetAPrice, 'E', -1, 64), - AssetBId: uint32(liquidity.AssetBId), - AssetBName: assetB.AssetName, - AssetBAmount: liquidity.AssetB, - AssetBPrice: strconv.FormatFloat(assetBPrice, 'E', -1, 64), - FeeRate: liquidity.FeeRate, - TreasuryRate: liquidity.TreasuryRate, - TotalLpAmount: liquidity.LpAmount, - }) - } - return resp, nil -} diff --git a/service/apiserver/internal/logic/pair/getswapamountlogic.go b/service/apiserver/internal/logic/pair/getswapamountlogic.go deleted file mode 100644 index fd6e9eabe..000000000 --- a/service/apiserver/internal/logic/pair/getswapamountlogic.go +++ /dev/null @@ -1,73 +0,0 @@ -package pair - -import ( - "context" - "math/big" - - "github.com/zeromicro/go-zero/core/logx" - - "github.com/bnb-chain/zkbnb/common/chain" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/svc" - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" - types2 "github.com/bnb-chain/zkbnb/types" -) - -type GetSwapAmountLogic struct { - logx.Logger - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewGetSwapAmountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetSwapAmountLogic { - return &GetSwapAmountLogic{ - Logger: logx.WithContext(ctx), - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *GetSwapAmountLogic) GetSwapAmount(req *types.ReqGetSwapAmount) (*types.SwapAmount, error) { - deltaAmount, isTure := new(big.Int).SetString(req.AssetAmount, 10) - if !isTure { - logx.Errorf("fail to convert string: %s to int", req.AssetAmount) - return nil, types2.AppErrInvalidParam.RefineError("invalid AssetAmount") - } - - liquidity, err := l.svcCtx.StateFetcher.GetLatestLiquidity(int64(req.PairIndex)) - if err != nil { - if err == types2.DbErrNotFound { - return nil, types2.AppErrNotFound - } - return nil, types2.AppErrInternal - } - - if liquidity.AssetA == nil || liquidity.AssetB == nil { - logx.Errorf("invalid liquidity: %v", liquidity) - return nil, types2.AppErrInternal - } - - if int64(req.AssetId) != liquidity.AssetAId && int64(req.AssetId) != liquidity.AssetBId { - logx.Errorf("invalid liquidity asset ids: %v", liquidity) - return nil, types2.AppErrInvalidParam.RefineError("invalid AssetId") - } - - if liquidity.AssetA.Cmp(types2.ZeroBigInt) == 0 || liquidity.AssetB.Cmp(types2.ZeroBigInt) == 0 { - logx.Errorf("invalid liquidity asset amount: %v", liquidity) - return nil, types2.AppErrInvalidParam.RefineError("invalid PairIndex, empty liquidity or invalid pair") - } - - var assetAmount *big.Int - var toAssetId int64 - assetAmount, toAssetId, err = chain.ComputeDelta(liquidity.AssetA, liquidity.AssetB, liquidity.AssetAId, liquidity.AssetBId, - int64(req.AssetId), req.IsFrom, deltaAmount, liquidity.FeeRate) - if err != nil { - logx.Errorf("fail to compute delta, err: %s", err.Error()) - return nil, types2.AppErrInternal - } - assetName, _ := l.svcCtx.MemCache.GetAssetNameById(toAssetId) - return &types.SwapAmount{ - AssetId: uint32(toAssetId), - AssetName: assetName, - AssetAmount: assetAmount.String(), - }, nil -} diff --git a/service/apiserver/internal/logic/transaction/getnextnoncelogic.go b/service/apiserver/internal/logic/transaction/getnextnoncelogic.go index a1f00e88a..0f1e35f31 100644 --- a/service/apiserver/internal/logic/transaction/getnextnoncelogic.go +++ b/service/apiserver/internal/logic/transaction/getnextnoncelogic.go @@ -26,7 +26,7 @@ func NewGetNextNonceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetN } func (l *GetNextNonceLogic) GetNextNonce(req *types.ReqGetNextNonce) (*types.NextNonce, error) { - bc, err := core.NewBlockChainForDryRun(l.svcCtx.AccountModel, l.svcCtx.LiquidityModel, l.svcCtx.NftModel, + bc, err := core.NewBlockChainForDryRun(l.svcCtx.AccountModel, l.svcCtx.NftModel, l.svcCtx.TxPoolModel, l.svcCtx.AssetModel, l.svcCtx.SysConfigModel, l.svcCtx.RedisCache) if err != nil { return nil, err diff --git a/service/apiserver/internal/logic/transaction/sendtxlogic.go b/service/apiserver/internal/logic/transaction/sendtxlogic.go index a6165c83c..8fca79589 100644 --- a/service/apiserver/internal/logic/transaction/sendtxlogic.go +++ b/service/apiserver/internal/logic/transaction/sendtxlogic.go @@ -37,7 +37,7 @@ func (s *SendTxLogic) SendTx(req *types.ReqSendTx) (resp *types.TxHash, err erro } resp = &types.TxHash{} - bc, err := core.NewBlockChainForDryRun(s.svcCtx.AccountModel, s.svcCtx.LiquidityModel, s.svcCtx.NftModel, s.svcCtx.TxPoolModel, + bc, err := core.NewBlockChainForDryRun(s.svcCtx.AccountModel, s.svcCtx.NftModel, s.svcCtx.TxPoolModel, s.svcCtx.AssetModel, s.svcCtx.SysConfigModel, s.svcCtx.RedisCache) if err != nil { logx.Error("fail to init blockchain runner:", err) @@ -50,7 +50,6 @@ func (s *SendTxLogic) SendTx(req *types.ReqSendTx) (resp *types.TxHash, err erro GasFeeAssetId: types2.NilAssetId, GasFee: types2.NilAssetAmount, - PairIndex: types2.NilPairIndex, NftIndex: types2.NilNftIndex, CollectionId: types2.NilCollectionNonce, AssetId: types2.NilAssetId, diff --git a/service/apiserver/internal/logic/utils/converter.go b/service/apiserver/internal/logic/utils/converter.go index 754fa3509..fab43158d 100644 --- a/service/apiserver/internal/logic/utils/converter.go +++ b/service/apiserver/internal/logic/utils/converter.go @@ -15,7 +15,6 @@ func ConvertTx(tx *tx.Tx) *types.Tx { Index: tx.TxIndex, BlockHeight: tx.BlockHeight, NftIndex: tx.NftIndex, - PairIndex: tx.PairIndex, CollectionId: tx.CollectionId, AssetId: tx.AssetId, Amount: tx.TxAmount, diff --git a/service/apiserver/internal/svc/servicecontext.go b/service/apiserver/internal/svc/servicecontext.go index 107e96cf9..b76242ff7 100644 --- a/service/apiserver/internal/svc/servicecontext.go +++ b/service/apiserver/internal/svc/servicecontext.go @@ -11,7 +11,6 @@ import ( "github.com/bnb-chain/zkbnb/dao/asset" "github.com/bnb-chain/zkbnb/dao/block" "github.com/bnb-chain/zkbnb/dao/dbcache" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/dao/sysconfig" "github.com/bnb-chain/zkbnb/dao/tx" @@ -26,17 +25,15 @@ type ServiceContext struct { RedisCache dbcache.Cache MemCache *cache.MemCache - DB *gorm.DB - TxPoolModel tx.TxPoolModel - AccountModel account.AccountModel - AccountHistoryModel account.AccountHistoryModel - TxModel tx.TxModel - LiquidityModel liquidity.LiquidityModel - LiquidityHistoryModel liquidity.LiquidityHistoryModel - BlockModel block.BlockModel - NftModel nft.L2NftModel - AssetModel asset.AssetModel - SysConfigModel sysconfig.SysConfigModel + DB *gorm.DB + TxPoolModel tx.TxPoolModel + AccountModel account.AccountModel + AccountHistoryModel account.AccountHistoryModel + TxModel tx.TxModel + BlockModel block.BlockModel + NftModel nft.L2NftModel + AssetModel asset.AssetModel + SysConfigModel sysconfig.SysConfigModel PriceFetcher price.Fetcher StateFetcher state.Fetcher @@ -51,29 +48,26 @@ func NewServiceContext(c config.Config) *ServiceContext { txPoolModel := tx.NewTxPoolModel(db) accountModel := account.NewAccountModel(db) - liquidityModel := liquidity.NewLiquidityModel(db) nftModel := nft.NewL2NftModel(db) assetModel := asset.NewAssetModel(db) memCache := cache.NewMemCache(accountModel, assetModel, c.MemCache.AccountExpiration, c.MemCache.BlockExpiration, c.MemCache.TxExpiration, c.MemCache.AssetExpiration, c.MemCache.PriceExpiration) return &ServiceContext{ - Config: c, - RedisCache: redisCache, - MemCache: memCache, - DB: db, - TxPoolModel: txPoolModel, - AccountModel: accountModel, - AccountHistoryModel: account.NewAccountHistoryModel(db), - TxModel: tx.NewTxModel(db), - LiquidityModel: liquidityModel, - LiquidityHistoryModel: liquidity.NewLiquidityHistoryModel(db), - BlockModel: block.NewBlockModel(db), - NftModel: nftModel, - AssetModel: assetModel, - SysConfigModel: sysconfig.NewSysConfigModel(db), + Config: c, + RedisCache: redisCache, + MemCache: memCache, + DB: db, + TxPoolModel: txPoolModel, + AccountModel: accountModel, + AccountHistoryModel: account.NewAccountHistoryModel(db), + TxModel: tx.NewTxModel(db), + BlockModel: block.NewBlockModel(db), + NftModel: nftModel, + AssetModel: assetModel, + SysConfigModel: sysconfig.NewSysConfigModel(db), PriceFetcher: price.NewFetcher(memCache, assetModel, c.CoinMarketCap.Url, c.CoinMarketCap.Token), - StateFetcher: state.NewFetcher(redisCache, accountModel, liquidityModel, nftModel), + StateFetcher: state.NewFetcher(redisCache, accountModel, nftModel), } } diff --git a/service/apiserver/server.api b/service/apiserver/server.api index 369092c4f..a2b0e5bef 100644 --- a/service/apiserver/server.api +++ b/service/apiserver/server.api @@ -40,11 +40,6 @@ type ( Price string `json:"price"` } - AccountLp { - Index uint32 `json:"index"` - Amount string `json:"amount"` - } - Account { Status uint32 `json:"status"` Index int64 `json:"index"` @@ -52,7 +47,6 @@ type ( Pk string `json:"pk"` Nonce int64 `json:"nonce"` Assets []*AccountAsset `json:"assets"` - Lps []*AccountLp `json:"lps"` } SimpleAccount { @@ -255,85 +249,6 @@ service server-api { get /api/v1/search (ReqSearch) returns (Search) } -/* =========================== Pair ==========================*/ - -type ( - SwapAmount { - AssetId uint32 `json:"asset_id"` - AssetName string `json:"asset_name"` - AssetAmount string `json:"asset_amount"` - } - - Pair { - Index uint32 `json:"index"` - AssetAId uint32 `json:"asset_a_id"` - AssetAName string `json:"asset_a_name"` - AssetAAmount string `json:"asset_a_amount"` - AssetAPrice string `json:"asset_a_price"` - AssetBId uint32 `json:"asset_b_id"` - AssetBName string `json:"asset_b_name"` - AssetBPrice string `json:"asset_b_price"` - AssetBAmount string `json:"asset_b_amount"` - FeeRate int64 `json:"fee_rate"` - TreasuryRate int64 `json:"treasury_rate"` - TotalLpAmount string `json:"total_lp_amount"` - } - Pairs { - Pairs []*Pair `json:"pairs"` - } - - LpValue { - AssetAId uint32 `json:"asset_a_id"` - AssetAName string `json:"asset_a_name"` - AssetAPrice string `json:"asset_a_price"` - AssetAAmount string `json:"asset_a_amount"` - AssetBId uint32 `json:"asset_b_id"` - AssetBName string `json:"asset_b_name"` - AssetBPrice string `json:"asset_b_price"` - AssetBAmount string `json:"asset_b_amount"` - } -) - -type ( - ReqGetSwapAmount { - PairIndex uint32 `form:"pair_index"` - AssetId uint32 `form:"asset_id"` - AssetAmount string `form:"asset_amount"` - IsFrom bool `form:"is_from"` - } - - ReqGetLpValue { - PairIndex uint32 `form:"pair_index"` - LpAmount string `form:"lp_amount"` - } - - ReqGetPair { - Index uint32 `form:"index"` - } -) - -@server( - group: pair -) - -service server-api { - @doc "Get swap amount for a specific liquidity pair and in asset amount" - @handler GetSwapAmount - get /api/v1/swapAmount (ReqGetSwapAmount) returns (SwapAmount) - - @doc "Get liquidity pairs" - @handler GetPairs - get /api/v1/pairs returns (Pairs) - - @doc "Get liquidity pool amount for a specific liquidity pair" - @handler GetLpValue - get /api/v1/lpValue (ReqGetLpValue) returns (LpValue) - - @doc "Get liquidity pool info by its index" - @handler GetPair - get /api/v1/pair (ReqGetPair) returns (Pair) -} - /* ======================= Transaction =======================*/ type ( @@ -348,7 +263,6 @@ type ( GasFee string `json:"gas_fee"` NftIndex int64 `json:"nft_index"` CollectionId int64 `json:"collection_id"` - PairIndex int64 `json:"pair_index"` AssetId int64 `json:"asset_id"` AssetName string `json:"asset_name"` NativeAddress string `json:"native_address"` diff --git a/service/apiserver/test/getlpvalue_test.go b/service/apiserver/test/getlpvalue_test.go deleted file mode 100644 index e36639858..000000000 --- a/service/apiserver/test/getlpvalue_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package test - -import ( - "encoding/json" - "fmt" - "io" - "math" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" -) - -func (s *ApiServerSuite) TestGetLpValue() { - type args struct { - pairIndex int - lpAmount string - } - - type testcase struct { - name string - args args - httpCode int - } - - tests := []testcase{ - {"not found", args{math.MaxInt, "2"}, 400}, - } - - statusCode, pairs := GetPairs(s, 0, 100) - if statusCode == http.StatusOK && len(pairs.Pairs) > 0 { - for _, pair := range pairs.Pairs { - if pair.TotalLpAmount != "" && pair.TotalLpAmount != "0" { - tests = append(tests, []testcase{ - {"found by index", args{int(pair.Index), "9000"}, 200}, - }...) - break - } - } - } - - for _, tt := range tests { - s.T().Run(tt.name, func(t *testing.T) { - httpCode, result := GetLpValue(s, tt.args.pairIndex, tt.args.lpAmount) - assert.Equal(t, tt.httpCode, httpCode) - if httpCode == http.StatusOK { - assert.NotNil(t, result.AssetAId) - assert.NotNil(t, result.AssetAName) - assert.NotNil(t, result.AssetAAmount) - assert.NotNil(t, result.AssetBId) - assert.NotNil(t, result.AssetBName) - assert.NotNil(t, result.AssetBAmount) - fmt.Printf("result: %+v \n", result) - } - }) - } - -} - -func GetLpValue(s *ApiServerSuite, pairIndex int, lpAmount string) (int, *types.LpValue) { - resp, err := http.Get(fmt.Sprintf("%s/api/v1/lpValue?pair_index=%d&lp_amount=%s", s.url, pairIndex, lpAmount)) - assert.NoError(s.T(), err) - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - assert.NoError(s.T(), err) - - if resp.StatusCode != http.StatusOK { - return resp.StatusCode, nil - } - result := types.LpValue{} - //nolint: errcheck - json.Unmarshal(body, &result) - return resp.StatusCode, &result -} diff --git a/service/apiserver/test/getpair_test.go b/service/apiserver/test/getpair_test.go deleted file mode 100644 index f7de4b0b7..000000000 --- a/service/apiserver/test/getpair_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package test - -import ( - "encoding/json" - "fmt" - "io" - "math" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" -) - -func (s *ApiServerSuite) TestGetPair() { - type testcase struct { - name string - args int //pair index - httpCode int - } - - tests := []testcase{ - {"not found", math.MaxInt, 400}, - } - - statusCode, pairs := GetPairs(s, 0, 100) - if statusCode == http.StatusOK && len(pairs.Pairs) > 0 { - tests = append(tests, []testcase{ - {"found by index", int(pairs.Pairs[0].Index), 200}, - }...) - } - - for _, tt := range tests { - s.T().Run(tt.name, func(t *testing.T) { - httpCode, result := GetPair(s, tt.args) - assert.Equal(t, tt.httpCode, httpCode) - if httpCode == http.StatusOK { - assert.NotNil(t, result.AssetAId) - assert.NotNil(t, result.AssetBId) - assert.NotNil(t, result.AssetAAmount) - assert.NotNil(t, result.AssetBAmount) - assert.NotNil(t, result.TotalLpAmount) - fmt.Printf("result: %+v \n", result) - } - }) - } - -} - -func GetPair(s *ApiServerSuite, pairIndex int) (int, *types.Pair) { - resp, err := http.Get(fmt.Sprintf("%s/api/v1/pair?index=%d", s.url, pairIndex)) - assert.NoError(s.T(), err) - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - assert.NoError(s.T(), err) - - if resp.StatusCode != http.StatusOK { - return resp.StatusCode, nil - } - result := types.Pair{} - //nolint: errcheck - json.Unmarshal(body, &result) - return resp.StatusCode, &result -} diff --git a/service/apiserver/test/getpairs_test.go b/service/apiserver/test/getpairs_test.go deleted file mode 100644 index cde54028c..000000000 --- a/service/apiserver/test/getpairs_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package test - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" -) - -func (s *ApiServerSuite) TestGetPairs() { - - type args struct { - offset int - limit int - } - tests := []struct { - name string - args args - httpCode int - }{ - {"found", args{0, 10}, 200}, - } - - for _, tt := range tests { - s.T().Run(tt.name, func(t *testing.T) { - httpCode, result := GetPairs(s, tt.args.offset, tt.args.limit) - assert.Equal(t, tt.httpCode, httpCode) - if httpCode == http.StatusOK { - assert.NotNil(t, result.Pairs) - if len(result.Pairs) > 0 { - assert.NotNil(t, result.Pairs[0].Index) - assert.NotNil(t, result.Pairs[0].AssetAName) - assert.NotNil(t, result.Pairs[0].AssetBName) - assert.NotNil(t, result.Pairs[0].AssetAId) - assert.NotNil(t, result.Pairs[0].AssetBId) - assert.NotNil(t, result.Pairs[0].AssetAAmount) - assert.NotNil(t, result.Pairs[0].AssetBAmount) - assert.NotNil(t, result.Pairs[0].FeeRate) - assert.NotNil(t, result.Pairs[0].TreasuryRate) - } - fmt.Printf("result: %+v \n", result) - } - }) - } - -} - -func GetPairs(s *ApiServerSuite, offset, limit int) (int, *types.Pairs) { - resp, err := http.Get(fmt.Sprintf("%s/api/v1/pairs?offset=%d&limit=%d", s.url, offset, limit)) - assert.NoError(s.T(), err) - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - assert.NoError(s.T(), err) - - if resp.StatusCode != http.StatusOK { - return resp.StatusCode, nil - } - result := types.Pairs{} - //nolint: errcheck - json.Unmarshal(body, &result) - return resp.StatusCode, &result -} diff --git a/service/apiserver/test/getswapamount_test.go b/service/apiserver/test/getswapamount_test.go deleted file mode 100644 index 82630ccaf..000000000 --- a/service/apiserver/test/getswapamount_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package test - -import ( - "encoding/json" - "fmt" - "io" - "math" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/bnb-chain/zkbnb/service/apiserver/internal/types" -) - -func (s *ApiServerSuite) TestGetSwapAmount() { - type args struct { - pairIndex uint32 - assetId uint32 - assetAmount string - isFrom bool - } - - type testcase struct { - name string - args args - httpCode int - } - - tests := []testcase{ - {"not found", args{math.MaxUint32, math.MaxUint32, "1", true}, 400}, - } - - statusCode, pairs := GetPairs(s, 0, 100) - if statusCode == http.StatusOK && len(pairs.Pairs) > 0 { - for _, pair := range pairs.Pairs { - if pair.TotalLpAmount != "" && pair.TotalLpAmount != "0" { - tests = append(tests, []testcase{ - {"found by index with from is true", args{pair.Index, pair.AssetAId, "9000", true}, 200}, - {"found by index with from is true", args{pair.Index, pair.AssetBId, "9000", true}, 200}, - {"found by index with from is false", args{pair.Index, pair.AssetAId, "9000", false}, 200}, - {"found by index with from is false", args{pair.Index, pair.AssetBId, "9000", false}, 200}, - }...) - break - } - } - } - - for _, tt := range tests { - s.T().Run(tt.name, func(t *testing.T) { - httpCode, result := GetSwapAmount(s, tt.args.pairIndex, tt.args.assetId, tt.args.assetAmount, tt.args.isFrom) - assert.Equal(t, tt.httpCode, httpCode) - if httpCode == http.StatusOK { - assert.NotNil(t, result.AssetId) - assert.NotNil(t, result.AssetAmount) - fmt.Printf("result: %+v \n", result) - } - }) - } - -} - -func GetSwapAmount(s *ApiServerSuite, pairIndex, assetId uint32, assetAmount string, isFrom bool) (int, *types.SwapAmount) { - resp, err := http.Get(fmt.Sprintf("%s/api/v1/swapAmount?pair_index=%d&asset_id=%d&asset_amount=%s&is_from=%v", s.url, pairIndex, assetId, assetAmount, isFrom)) - assert.NoError(s.T(), err) - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - assert.NoError(s.T(), err) - - if resp.StatusCode != http.StatusOK { - return resp.StatusCode, nil - } - result := types.SwapAmount{} - //nolint: errcheck - json.Unmarshal(body, &result) - return resp.StatusCode, &result -} diff --git a/service/committer/committer/committer.go b/service/committer/committer/committer.go index 80d77d1e2..d327c6f50 100644 --- a/service/committer/committer/committer.go +++ b/service/committer/committer/committer.go @@ -138,7 +138,10 @@ func (c *Committer) Run() { if c.shouldCommit(curBlock) { logx.Infof("commit new block, height=%d, blockSize=%d", curBlock.BlockHeight, curBlock.BlockSize) curBlock, err = c.commitNewBlock(curBlock) + logx.Infof("commit new block success") + if err != nil { + logx.Errorf("commit new block error, err=%s", err.Error()) panic("commit new block failed: " + err.Error()) } } @@ -242,27 +245,6 @@ func (c *Committer) commitNewBlock(curBlock *block.Block) (*block.Block, error) return err } } - // create new liquidity - if len(blockStates.PendingNewLiquidity) != 0 { - err = c.bc.DB().LiquidityModel.CreateLiquidityInTransact(tx, blockStates.PendingNewLiquidity) - if err != nil { - return err - } - } - // update liquidity - if len(blockStates.PendingUpdateLiquidity) != 0 { - err = c.bc.DB().LiquidityModel.UpdateLiquidityInTransact(tx, blockStates.PendingUpdateLiquidity) - if err != nil { - return err - } - } - // create new liquidity history - if len(blockStates.PendingNewLiquidityHistory) != 0 { - err = c.bc.DB().LiquidityHistoryModel.CreateLiquidityHistoriesInTransact(tx, blockStates.PendingNewLiquidityHistory) - if err != nil { - return err - } - } // create new nft if len(blockStates.PendingNewNft) != 0 { err = c.bc.DB().L2NftModel.CreateNftsInTransact(tx, blockStates.PendingNewNft) diff --git a/service/monitor/monitor/monitor_governance_blocks.go b/service/monitor/monitor/monitor_governance_blocks.go index f66246c93..df083576b 100644 --- a/service/monitor/monitor/monitor_governance_blocks.go +++ b/service/monitor/monitor/monitor_governance_blocks.go @@ -210,7 +210,7 @@ func (m *Monitor) MonitorGovernanceBlocks() (err error) { return err } syncedBlock := &l1syncedblock.L1SyncedBlock{ - L1BlockHeight: int64(endHeight), + L1BlockHeight: endHeight, BlockInfo: string(eventInfosBytes), Type: l1syncedblock.TypeGovernance, } diff --git a/service/monitor/monitor/monitor_priority_requests.go b/service/monitor/monitor/monitor_priority_requests.go index af8ed66e5..207784f8b 100644 --- a/service/monitor/monitor/monitor_priority_requests.go +++ b/service/monitor/monitor/monitor_priority_requests.go @@ -64,7 +64,6 @@ func (m *Monitor) MonitorPriorityRequests() error { GasFeeAssetId: types.NilAssetId, GasFee: types.NilAssetAmount, - PairIndex: types.NilPairIndex, NftIndex: types.NilNftIndex, CollectionId: types.NilCollectionNonce, AssetId: types.NilAssetId, @@ -90,30 +89,6 @@ func (m *Monitor) MonitorPriorityRequests() error { return err } - case TxTypeCreatePair: - txInfo, err := chain.ParseCreatePairPubData(common.FromHex(request.Pubdata)) - if err != nil { - return fmt.Errorf("unable to parse registerZNS pub data: %v", err) - } - - poolTx.TxType = int64(txInfo.TxType) - txInfoBytes, err = json.Marshal(txInfo) - if err != nil { - return fmt.Errorf("unable to serialize request info : %v", err) - } - - case TxTypeUpdatePairRate: - txInfo, err := chain.ParseUpdatePairRatePubData(common.FromHex(request.Pubdata)) - if err != nil { - return fmt.Errorf("unable to parse update pair rate pub data: %v", err) - } - - poolTx.TxType = int64(txInfo.TxType) - txInfoBytes, err = json.Marshal(txInfo) - if err != nil { - return fmt.Errorf("unable to serialize request info : %v", err) - } - case TxTypeDeposit: txInfo, err := chain.ParseDepositPubData(common.FromHex(request.Pubdata)) if err != nil { diff --git a/service/monitor/monitor/types.go b/service/monitor/monitor/types.go index d8744df17..592f375a2 100644 --- a/service/monitor/monitor/types.go +++ b/service/monitor/monitor/types.go @@ -51,13 +51,11 @@ const ( PendingStatus = priorityrequest.PendingStatus - TxTypeRegisterZns = types.TxTypeRegisterZns - TxTypeCreatePair = types.TxTypeCreatePair - TxTypeUpdatePairRate = types.TxTypeUpdatePairRate - TxTypeDeposit = types.TxTypeDeposit - TxTypeDepositNft = types.TxTypeDepositNft - TxTypeFullExit = types.TxTypeFullExit - TxTypeFullExitNft = types.TxTypeFullExitNft + TxTypeRegisterZns = types.TxTypeRegisterZns + TxTypeDeposit = types.TxTypeDeposit + TxTypeDepositNft = types.TxTypeDepositNft + TxTypeFullExit = types.TxTypeFullExit + TxTypeFullExitNft = types.TxTypeFullExitNft ) var ( diff --git a/service/witness/witness/witness.go b/service/witness/witness/witness.go index 612ed27ca..1a4304c47 100644 --- a/service/witness/witness/witness.go +++ b/service/witness/witness/witness.go @@ -18,7 +18,6 @@ import ( "github.com/bnb-chain/zkbnb/dao/account" "github.com/bnb-chain/zkbnb/dao/block" "github.com/bnb-chain/zkbnb/dao/blockwitness" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/dao/proof" "github.com/bnb-chain/zkbnb/service/witness/config" @@ -40,22 +39,20 @@ type Witness struct { helper *utils.WitnessHelper // Trees - treeCtx *tree.Context - accountTree smt.SparseMerkleTree - assetTrees *tree.AssetTreeCache - liquidityTree smt.SparseMerkleTree - nftTree smt.SparseMerkleTree - taskPool *ants.Pool + treeCtx *tree.Context + accountTree smt.SparseMerkleTree + assetTrees *tree.AssetTreeCache + nftTree smt.SparseMerkleTree + taskPool *ants.Pool // The data access object - db *gorm.DB - blockModel block.BlockModel - accountModel account.AccountModel - accountHistoryModel account.AccountHistoryModel - liquidityHistoryModel liquidity.LiquidityHistoryModel - nftHistoryModel nft.L2NftHistoryModel - proofModel proof.ProofModel - blockWitnessModel blockwitness.BlockWitnessModel + db *gorm.DB + blockModel block.BlockModel + accountModel account.AccountModel + accountHistoryModel account.AccountHistoryModel + nftHistoryModel nft.L2NftHistoryModel + proofModel proof.ProofModel + blockWitnessModel blockwitness.BlockWitnessModel } func NewWitness(c config.Config) (*Witness, error) { @@ -66,15 +63,14 @@ func NewWitness(c config.Config) (*Witness, error) { } w := &Witness{ - config: c, - db: db, - blockModel: block.NewBlockModel(db), - blockWitnessModel: blockwitness.NewBlockWitnessModel(db), - accountModel: account.NewAccountModel(db), - accountHistoryModel: account.NewAccountHistoryModel(db), - liquidityHistoryModel: liquidity.NewLiquidityHistoryModel(db), - nftHistoryModel: nft.NewL2NftHistoryModel(db), - proofModel: proof.NewProofModel(db), + config: c, + db: db, + blockModel: block.NewBlockModel(db), + blockWitnessModel: blockwitness.NewBlockWitnessModel(db), + accountModel: account.NewAccountModel(db), + accountHistoryModel: account.NewAccountHistoryModel(db), + nftHistoryModel: nft.NewL2NftHistoryModel(db), + proofModel: proof.NewProofModel(db), } err = w.initState() return w, err @@ -117,11 +113,6 @@ func (w *Witness) initState() error { return fmt.Errorf("initMerkleTree error: %v", err) } - w.liquidityTree, err = tree.InitLiquidityTree(w.liquidityHistoryModel, witnessHeight, - treeCtx) - if err != nil { - return fmt.Errorf("initLiquidityTree error: %v", err) - } w.nftTree, err = tree.InitNftTree(w.nftHistoryModel, witnessHeight, treeCtx) if err != nil { @@ -132,7 +123,7 @@ func (w *Witness) initState() error { return err } w.taskPool = taskPool - w.helper = utils.NewWitnessHelper(w.treeCtx, w.accountTree, w.liquidityTree, w.nftTree, w.assetTrees, w.accountModel) + w.helper = utils.NewWitnessHelper(w.treeCtx, w.accountTree, w.nftTree, w.assetTrees, w.accountModel) return nil } @@ -165,7 +156,7 @@ func (w *Witness) GenerateBlockWitness() (err error) { return fmt.Errorf("failed to construct block witness, block:%d, err: %v", block.BlockHeight, err) } // Step2: commit trees for witness - err = tree.CommitTrees(w.taskPool, uint64(latestVerifiedBlockNr), w.accountTree, w.assetTrees, w.liquidityTree, w.nftTree) + err = tree.CommitTrees(w.taskPool, uint64(latestVerifiedBlockNr), w.accountTree, w.assetTrees, w.nftTree) if err != nil { return fmt.Errorf("unable to commit trees after txs is executed, block:%d, error: %v", block.BlockHeight, err) } @@ -173,7 +164,7 @@ func (w *Witness) GenerateBlockWitness() (err error) { err = w.blockWitnessModel.CreateBlockWitness(blockWitness) if err != nil { // rollback trees - rollBackErr := tree.RollBackTrees(w.taskPool, uint64(block.BlockHeight)-1, w.accountTree, w.assetTrees, w.liquidityTree, w.nftTree) + rollBackErr := tree.RollBackTrees(w.taskPool, uint64(block.BlockHeight)-1, w.accountTree, w.assetTrees, w.nftTree) if rollBackErr != nil { logx.Errorf("unable to rollback trees %v", rollBackErr) } @@ -270,7 +261,7 @@ func (w *Witness) constructBlockWitness(block *block.Block, latestVerifiedBlockN emptyTxCount := int(block.BlockSize) - len(block.Txs) for i := 0; i < emptyTxCount; i++ { - txsWitness = append(txsWitness, circuit.EmptyTx()) + txsWitness = append(txsWitness, circuit.EmptyTx(newStateRoot)) } if common.Bytes2Hex(newStateRoot) != block.StateRoot { return nil, errors.New("state root doesn't match") diff --git a/tools/dbinitializer/main.go b/tools/dbinitializer/main.go index 518390db6..4c0568dfc 100644 --- a/tools/dbinitializer/main.go +++ b/tools/dbinitializer/main.go @@ -34,7 +34,6 @@ import ( "github.com/bnb-chain/zkbnb/dao/compressedblock" "github.com/bnb-chain/zkbnb/dao/l1rolluptx" "github.com/bnb-chain/zkbnb/dao/l1syncedblock" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/dao/priorityrequest" "github.com/bnb-chain/zkbnb/dao/proof" @@ -59,24 +58,22 @@ type contractAddr struct { } type dao struct { - sysConfigModel sysconfig.SysConfigModel - accountModel account.AccountModel - accountHistoryModel account.AccountHistoryModel - assetModel asset.AssetModel - txPoolModel tx.TxPoolModel - txDetailModel tx.TxDetailModel - txModel tx.TxModel - blockModel block.BlockModel - compressedBlockModel compressedblock.CompressedBlockModel - blockWitnessModel blockwitness.BlockWitnessModel - proofModel proof.ProofModel - l1SyncedBlockModel l1syncedblock.L1SyncedBlockModel - priorityRequestModel priorityrequest.PriorityRequestModel - l1RollupTModel l1rolluptx.L1RollupTxModel - liquidityModel liquidity.LiquidityModel - liquidityHistoryModel liquidity.LiquidityHistoryModel - nftModel nft.L2NftModel - nftHistoryModel nft.L2NftHistoryModel + sysConfigModel sysconfig.SysConfigModel + accountModel account.AccountModel + accountHistoryModel account.AccountHistoryModel + assetModel asset.AssetModel + txPoolModel tx.TxPoolModel + txDetailModel tx.TxDetailModel + txModel tx.TxModel + blockModel block.BlockModel + compressedBlockModel compressedblock.CompressedBlockModel + blockWitnessModel blockwitness.BlockWitnessModel + proofModel proof.ProofModel + l1SyncedBlockModel l1syncedblock.L1SyncedBlockModel + priorityRequestModel priorityrequest.PriorityRequestModel + l1RollupTModel l1rolluptx.L1RollupTxModel + nftModel nft.L2NftModel + nftHistoryModel nft.L2NftHistoryModel } func Initialize( @@ -95,24 +92,22 @@ func Initialize( logx.Infof("init configs: %s", string(unmarshal)) dao := &dao{ - sysConfigModel: sysconfig.NewSysConfigModel(db), - accountModel: account.NewAccountModel(db), - accountHistoryModel: account.NewAccountHistoryModel(db), - assetModel: asset.NewAssetModel(db), - txPoolModel: tx.NewTxPoolModel(db), - txDetailModel: tx.NewTxDetailModel(db), - txModel: tx.NewTxModel(db), - blockModel: block.NewBlockModel(db), - compressedBlockModel: compressedblock.NewCompressedBlockModel(db), - blockWitnessModel: blockwitness.NewBlockWitnessModel(db), - proofModel: proof.NewProofModel(db), - l1SyncedBlockModel: l1syncedblock.NewL1SyncedBlockModel(db), - priorityRequestModel: priorityrequest.NewPriorityRequestModel(db), - l1RollupTModel: l1rolluptx.NewL1RollupTxModel(db), - liquidityModel: liquidity.NewLiquidityModel(db), - liquidityHistoryModel: liquidity.NewLiquidityHistoryModel(db), - nftModel: nft.NewL2NftModel(db), - nftHistoryModel: nft.NewL2NftHistoryModel(db), + sysConfigModel: sysconfig.NewSysConfigModel(db), + accountModel: account.NewAccountModel(db), + accountHistoryModel: account.NewAccountHistoryModel(db), + assetModel: asset.NewAssetModel(db), + txPoolModel: tx.NewTxPoolModel(db), + txDetailModel: tx.NewTxDetailModel(db), + txModel: tx.NewTxModel(db), + blockModel: block.NewBlockModel(db), + compressedBlockModel: compressedblock.NewCompressedBlockModel(db), + blockWitnessModel: blockwitness.NewBlockWitnessModel(db), + proofModel: proof.NewProofModel(db), + l1SyncedBlockModel: l1syncedblock.NewL1SyncedBlockModel(db), + priorityRequestModel: priorityrequest.NewPriorityRequestModel(db), + l1RollupTModel: l1rolluptx.NewL1RollupTxModel(db), + nftModel: nft.NewL2NftModel(db), + nftHistoryModel: nft.NewL2NftHistoryModel(db), } dropTables(dao) @@ -126,9 +121,6 @@ func initSysConfig(svrConf *contractAddr, bscTestNetworkRPC, localTestNetworkRPC // to config gas for different transaction types, need to be evaluated and tune these values bnbGasFee := make(map[int]int64) bnbGasFee[types.TxTypeTransfer] = 10000000000000 - bnbGasFee[types.TxTypeSwap] = 12000000000000 - bnbGasFee[types.TxTypeAddLiquidity] = 12000000000000 - bnbGasFee[types.TxTypeRemoveLiquidity] = 12000000000000 bnbGasFee[types.TxTypeWithdraw] = 20000000000000 bnbGasFee[types.TxTypeCreateCollection] = 10000000000000 bnbGasFee[types.TxTypeMintNft] = 10000000000000 @@ -228,8 +220,6 @@ func dropTables(dao *dao) { assert.Nil(nil, dao.l1SyncedBlockModel.DropL1SyncedBlockTable()) assert.Nil(nil, dao.priorityRequestModel.DropPriorityRequestTable()) assert.Nil(nil, dao.l1RollupTModel.DropL1RollupTxTable()) - assert.Nil(nil, dao.liquidityModel.DropLiquidityTable()) - assert.Nil(nil, dao.liquidityHistoryModel.DropLiquidityHistoryTable()) assert.Nil(nil, dao.nftModel.DropL2NftTable()) assert.Nil(nil, dao.nftHistoryModel.DropL2NftHistoryTable()) } @@ -249,8 +239,6 @@ func initTable(dao *dao, svrConf *contractAddr, bscTestNetworkRPC, localTestNetw assert.Nil(nil, dao.l1SyncedBlockModel.CreateL1SyncedBlockTable()) assert.Nil(nil, dao.priorityRequestModel.CreatePriorityRequestTable()) assert.Nil(nil, dao.l1RollupTModel.CreateL1RollupTxTable()) - assert.Nil(nil, dao.liquidityModel.CreateLiquidityTable()) - assert.Nil(nil, dao.liquidityHistoryModel.CreateLiquidityHistoryTable()) assert.Nil(nil, dao.nftModel.CreateL2NftTable()) assert.Nil(nil, dao.nftHistoryModel.CreateL2NftHistoryTable()) rowsAffected, err := dao.assetModel.CreateAssets(initAssetsInfo()) diff --git a/tools/recovery/internal/svc/servicecontext.go b/tools/recovery/internal/svc/servicecontext.go index 9dfa7e934..23a65c705 100644 --- a/tools/recovery/internal/svc/servicecontext.go +++ b/tools/recovery/internal/svc/servicecontext.go @@ -6,7 +6,6 @@ import ( "gorm.io/gorm" "github.com/bnb-chain/zkbnb/dao/account" - "github.com/bnb-chain/zkbnb/dao/liquidity" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/tools/recovery/internal/config" ) @@ -14,10 +13,9 @@ import ( type ServiceContext struct { Config config.Config - AccountModel account.AccountModel - AccountHistoryModel account.AccountHistoryModel - LiquidityHistoryModel liquidity.LiquidityHistoryModel - NftHistoryModel nft.L2NftHistoryModel + AccountModel account.AccountModel + AccountHistoryModel account.AccountHistoryModel + NftHistoryModel nft.L2NftHistoryModel } func NewServiceContext(c config.Config) *ServiceContext { @@ -26,10 +24,9 @@ func NewServiceContext(c config.Config) *ServiceContext { logx.Errorf("gorm connect db error, err = %s", err.Error()) } return &ServiceContext{ - Config: c, - AccountModel: account.NewAccountModel(db), - AccountHistoryModel: account.NewAccountHistoryModel(db), - LiquidityHistoryModel: liquidity.NewLiquidityHistoryModel(db), - NftHistoryModel: nft.NewL2NftHistoryModel(db), + Config: c, + AccountModel: account.NewAccountModel(db), + AccountHistoryModel: account.NewAccountHistoryModel(db), + NftHistoryModel: nft.NewL2NftHistoryModel(db), } } diff --git a/tools/recovery/recovery.go b/tools/recovery/recovery.go index 3722c80b9..776cb4c0c 100644 --- a/tools/recovery/recovery.go +++ b/tools/recovery/recovery.go @@ -54,15 +54,6 @@ func RecoveryTreeDB( logx.Error("InitMerkleTree error:", err) return } - // dbinitializer liquidityTree - _, err = tree.InitLiquidityTree( - ctx.LiquidityHistoryModel, - blockHeight, - treeCtx) - if err != nil { - logx.Errorf("InitLiquidityTree error: %s", err.Error()) - return - } // dbinitializer nftTree _, err = tree.InitNftTree( ctx.NftHistoryModel, diff --git a/tree/account_tree.go b/tree/account_tree.go index 2b4c53e22..855ce7166 100644 --- a/tree/account_tree.go +++ b/tree/account_tree.go @@ -191,7 +191,6 @@ func reloadAccountTreeFromRDB( for assetId, assetInfo := range accountInfo.AssetInfo { hashVal, err := AssetToNode( assetInfo.Balance.String(), - assetInfo.LpAmount.String(), assetInfo.OfferCanceledOrFinalized.String(), ) if err != nil { @@ -225,8 +224,8 @@ func reloadAccountTreeFromRDB( return nil } -func AssetToNode(balance string, lpAmount string, offerCanceledOrFinalized string) (hashVal []byte, err error) { - hashVal, err = ComputeAccountAssetLeafHash(balance, lpAmount, offerCanceledOrFinalized) +func AssetToNode(balance string, offerCanceledOrFinalized string) (hashVal []byte, err error) { + hashVal, err = ComputeAccountAssetLeafHash(balance, offerCanceledOrFinalized) if err != nil { logx.Errorf("unable to compute asset leaf hash: %s", err.Error()) return nil, err diff --git a/tree/hash_test.go b/tree/hash_test.go new file mode 100644 index 000000000..ec9caaa87 --- /dev/null +++ b/tree/hash_test.go @@ -0,0 +1,11 @@ +package tree + +import ( + "encoding/hex" + "testing" +) + +func TestHash(t *testing.T) { + emptyHash := EmptyAccountAssetNodeHash() + println(hex.EncodeToString(emptyHash)) +} diff --git a/tree/liquidity_tree.go b/tree/liquidity_tree.go deleted file mode 100644 index a8928b2f1..000000000 --- a/tree/liquidity_tree.go +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package tree - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" - "github.com/zeromicro/go-zero/core/logx" - - bsmt "github.com/bnb-chain/zkbnb-smt" - "github.com/bnb-chain/zkbnb/dao/liquidity" - "github.com/bnb-chain/zkbnb/types" -) - -func InitLiquidityTree( - liquidityHistoryModel liquidity.LiquidityHistoryModel, - blockHeight int64, - ctx *Context, -) ( - liquidityTree bsmt.SparseMerkleTree, err error, -) { - - liquidityTree, err = bsmt.NewBASSparseMerkleTree(bsmt.NewHasher(mimc.NewMiMC()), - SetNamespace(ctx, LiquidityPrefix), LiquidityTreeHeight, NilLiquidityNodeHash, - ctx.Options(blockHeight)...) - if err != nil { - logx.Errorf("unable to create tree from db: %s", err.Error()) - return nil, err - } - - if ctx.IsLoad() { - nums, err := liquidityHistoryModel.GetLatestLiquidityCountByBlockHeight(blockHeight) - if err != nil { - logx.Errorf("unable to get latest liquidity assets: %s", err.Error()) - return nil, err - } - for i := 0; i < int(nums); i += ctx.BatchReloadSize() { - err := loadLiquidityTreeFromRDB( - liquidityHistoryModel, blockHeight, - i, i+ctx.BatchReloadSize(), liquidityTree) - if err != nil { - return nil, err - } - _, err = liquidityTree.Commit(nil) - if err != nil { - logx.Errorf("unable to commit liquidity tree: %s", err.Error()) - return nil, err - } - } - - return liquidityTree, nil - } - - // It's not loading from RDB, need to check tree version - if liquidityTree.LatestVersion() > bsmt.Version(blockHeight) && !liquidityTree.IsEmpty() { - logx.Infof("liquidity tree version [%d] is higher than block, rollback to %d", liquidityTree.LatestVersion(), blockHeight) - err := liquidityTree.Rollback(bsmt.Version(blockHeight)) - if err != nil { - logx.Errorf("unable to rollback liquidity tree: %s, version: %d", err.Error(), blockHeight) - return nil, err - } - } - - return liquidityTree, nil -} - -func loadLiquidityTreeFromRDB( - liquidityHistoryModel liquidity.LiquidityHistoryModel, - blockHeight int64, - offset, limit int, - liquidityTree bsmt.SparseMerkleTree, -) error { - liquidityAssets, err := liquidityHistoryModel.GetLatestLiquidityByBlockHeight(blockHeight, - limit, offset) - if err != nil { - if err != types.DbErrNotFound { - logx.Errorf("unable to get latest liquidity assets: %s", err.Error()) - return err - } - } - for _, liquidityAsset := range liquidityAssets { - pairIndex := liquidityAsset.PairIndex - hashVal, err := LiquidityAssetToNode( - liquidityAsset.AssetAId, liquidityAsset.AssetA, - liquidityAsset.AssetBId, liquidityAsset.AssetB, - liquidityAsset.LpAmount, liquidityAsset.KLast, - liquidityAsset.FeeRate, liquidityAsset.TreasuryAccountIndex, liquidityAsset.TreasuryRate) - if err != nil { - logx.Errorf("unable to convert liquidity asset to node: %s", err.Error()) - return err - } - err = liquidityTree.Set(uint64(pairIndex), hashVal) - if err != nil { - logx.Errorf("unable to write liquidity asset to tree: %s", err.Error()) - return err - } - } - return nil -} - -func LiquidityAssetToNode( - assetAId int64, - assetA string, - assetBId int64, - assetB string, - lpAmount string, - kLast string, - feeRate int64, - treasuryAccountIndex int64, - treasuryFeeRate int64, -) (hashVal []byte, err error) { - hashVal, err = ComputeLiquidityAssetLeafHash( - assetAId, assetA, - assetBId, assetB, - lpAmount, - kLast, - feeRate, - treasuryAccountIndex, - treasuryFeeRate, - ) - if err != nil { - logx.Errorf("unable to compute liquidity asset leaf hash: %s", err.Error()) - return nil, err - } - return hashVal, nil -} diff --git a/tree/types.go b/tree/types.go index a84bb4207..7385e2c16 100644 --- a/tree/types.go +++ b/tree/types.go @@ -18,21 +18,22 @@ package tree import ( + "encoding/hex" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" + "github.com/zeromicro/go-zero/core/logx" "github.com/bnb-chain/zkbnb-crypto/merkleTree" ) const ( - AccountTreeHeight = 32 - AssetTreeHeight = 16 - LiquidityTreeHeight = 16 - NftTreeHeight = 40 + AccountTreeHeight = 32 + AssetTreeHeight = 16 + NftTreeHeight = 40 ) const ( NFTPrefix = "nft:" - LiquidityPrefix = "liquidity:" AccountPrefix = "account:" AccountAssetPrefix = "account_asset:" ) @@ -41,11 +42,9 @@ var ( NilHash = merkleTree.NilHash NilStateRoot []byte NilAccountRoot []byte - NilLiquidityRoot []byte NilNftRoot []byte NilAccountAssetRoot []byte NilAccountNodeHash []byte - NilLiquidityNodeHash []byte NilNftNodeHash []byte NilAccountAssetNodeHash []byte ) @@ -62,7 +61,6 @@ func init() { } NilAccountNodeHash = EmptyAccountNodeHash() NilAccountRoot = NilAccountNodeHash - NilLiquidityNodeHash = EmptyLiquidityNodeHash() NilNftNodeHash = EmptyNftNodeHash() for i := 0; i < AccountTreeHeight; i++ { hFunc.Reset() @@ -70,13 +68,6 @@ func init() { hFunc.Write(NilAccountRoot) NilAccountRoot = hFunc.Sum(nil) } - NilLiquidityRoot = NilLiquidityNodeHash - for i := 0; i < LiquidityTreeHeight; i++ { - hFunc.Reset() - hFunc.Write(NilLiquidityRoot) - hFunc.Write(NilLiquidityRoot) - NilLiquidityRoot = hFunc.Sum(nil) - } NilNftRoot = NilNftNodeHash for i := 0; i < NftTreeHeight; i++ { hFunc.Reset() @@ -87,7 +78,8 @@ func init() { // nil state root hFunc.Reset() hFunc.Write(NilAccountRoot) - hFunc.Write(NilLiquidityRoot) hFunc.Write(NilNftRoot) NilStateRoot = hFunc.Sum(nil) + + logx.Infof("genesis state root: %s", hex.EncodeToString(NilStateRoot)) } diff --git a/tree/util.go b/tree/util.go index c183e4f75..288b7d651 100644 --- a/tree/util.go +++ b/tree/util.go @@ -57,38 +57,10 @@ func EmptyAccountAssetNodeHash() []byte { zero := big.NewInt(0).FillBytes(make([]byte, 32)) /* balance - lpAmount offerCanceledOrFinalized */ hFunc.Write(zero) hFunc.Write(zero) - hFunc.Write(zero) - return hFunc.Sum(nil) -} - -func EmptyLiquidityNodeHash() []byte { - hFunc := mimc.NewMiMC() - zero := big.NewInt(0).FillBytes(make([]byte, 32)) - /* - assetAId - assetA - assetBId - assetB - lpAmount - kLast - feeRate - treasuryAccountIndex - treasuryRate - */ - hFunc.Write(zero) - hFunc.Write(zero) - hFunc.Write(zero) - hFunc.Write(zero) - hFunc.Write(zero) - hFunc.Write(zero) - hFunc.Write(zero) - hFunc.Write(zero) - hFunc.Write(zero) return hFunc.Sum(nil) } @@ -119,12 +91,12 @@ func CommitTrees( version uint64, accountTree bsmt.SparseMerkleTree, assetTrees *AssetTreeCache, - liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { assetTreeChanges := assetTrees.GetChanges() defer assetTrees.CleanChanges() - totalTask := len(assetTreeChanges) + 3 + totalTask := len(assetTreeChanges) + 2 + errChan := make(chan error, totalTask) defer close(errChan) @@ -162,22 +134,6 @@ func CommitTrees( } } - err = pool.Submit(func() { - liquidityPrunedVersion := bsmt.Version(version) - if liquidityTree.LatestVersion() < liquidityPrunedVersion { - liquidityPrunedVersion = liquidityTree.LatestVersion() - } - ver, err := liquidityTree.Commit(&liquidityPrunedVersion) - if err != nil { - errChan <- errors.Wrapf(err, "unable to commit liquidity tree, tree ver: %d, prune ver: %d", ver, liquidityPrunedVersion) - return - } - errChan <- nil - }) - if err != nil { - return err - } - err = pool.Submit(func() { nftPrunedVersion := bsmt.Version(version) if nftTree.LatestVersion() < nftPrunedVersion { @@ -209,7 +165,6 @@ func RollBackTrees( version uint64, accountTree bsmt.SparseMerkleTree, assetTrees *AssetTreeCache, - liquidityTree bsmt.SparseMerkleTree, nftTree bsmt.SparseMerkleTree) error { assetTreeChanges := assetTrees.GetChanges() @@ -251,20 +206,6 @@ func RollBackTrees( } } - err = pool.Submit(func() { - if liquidityTree.LatestVersion() > ver && !liquidityTree.IsEmpty() { - err := liquidityTree.Rollback(ver) - if err != nil { - errChan <- errors.Wrapf(err, "unable to rollback liquidity tree, ver: %d", ver) - return - } - } - errChan <- nil - }) - if err != nil { - return err - } - err = pool.Submit(func() { if nftTree.LatestVersion() > ver && !nftTree.IsEmpty() { err := nftTree.Rollback(ver) @@ -314,7 +255,6 @@ func ComputeAccountLeafHash( func ComputeAccountAssetLeafHash( balance string, - lpAmount string, offerCanceledOrFinalized string, ) (hashVal []byte, err error) { hFunc := mimc.NewMiMC() @@ -323,10 +263,6 @@ func ComputeAccountAssetLeafHash( if err != nil { return nil, err } - err = common2.PaddingStringBigIntIntoBuf(&buf, lpAmount) - if err != nil { - return nil, err - } err = common2.PaddingStringBigIntIntoBuf(&buf, offerCanceledOrFinalized) if err != nil { return nil, err @@ -335,45 +271,6 @@ func ComputeAccountAssetLeafHash( return hFunc.Sum(nil), nil } -func ComputeLiquidityAssetLeafHash( - assetAId int64, - assetA string, - assetBId int64, - assetB string, - lpAmount string, - kLast string, - feeRate int64, - treasuryAccountIndex int64, - treasuryRate int64, -) (hashVal []byte, err error) { - hFunc := mimc.NewMiMC() - var buf bytes.Buffer - common2.PaddingInt64IntoBuf(&buf, assetAId) - err = common2.PaddingStringBigIntIntoBuf(&buf, assetA) - if err != nil { - return nil, err - } - common2.PaddingInt64IntoBuf(&buf, assetBId) - err = common2.PaddingStringBigIntIntoBuf(&buf, assetB) - if err != nil { - return nil, err - } - err = common2.PaddingStringBigIntIntoBuf(&buf, lpAmount) - if err != nil { - return nil, err - } - err = common2.PaddingStringBigIntIntoBuf(&buf, kLast) - if err != nil { - return nil, err - } - common2.PaddingInt64IntoBuf(&buf, feeRate) - common2.PaddingInt64IntoBuf(&buf, treasuryAccountIndex) - common2.PaddingInt64IntoBuf(&buf, treasuryRate) - hFunc.Write(buf.Bytes()) - hashVal = hFunc.Sum(nil) - return hashVal, nil -} - func ComputeNftAssetLeafHash( creatorAccountIndex int64, ownerAccountIndex int64, @@ -405,12 +302,10 @@ func ComputeNftAssetLeafHash( func ComputeStateRootHash( accountRoot []byte, - liquidityRoot []byte, nftRoot []byte, ) []byte { hFunc := mimc.NewMiMC() hFunc.Write(accountRoot) - hFunc.Write(liquidityRoot) hFunc.Write(nftRoot) return hFunc.Sum(nil) } diff --git a/types/account.go b/types/account.go index dff244c96..269ae1de9 100644 --- a/types/account.go +++ b/types/account.go @@ -24,9 +24,8 @@ import ( const ( FungibleAssetType = 1 - LiquidityAssetType = 2 - NftAssetType = 3 - CollectionNonceAssetType = 4 + NftAssetType = 2 + CollectionNonceAssetType = 3 BuyOfferType = 0 SellOfferType = 1 @@ -35,7 +34,6 @@ const ( type AccountAsset struct { AssetId int64 Balance *big.Int - LpAmount *big.Int OfferCanceledOrFinalized *big.Int } @@ -43,16 +41,14 @@ func (asset *AccountAsset) DeepCopy() *AccountAsset { return &AccountAsset{ AssetId: asset.AssetId, Balance: big.NewInt(0).Set(asset.Balance), - LpAmount: big.NewInt(0).Set(asset.LpAmount), OfferCanceledOrFinalized: big.NewInt(0).Set(asset.OfferCanceledOrFinalized), } } -func ConstructAccountAsset(assetId int64, balance *big.Int, lpAmount *big.Int, offerCanceledOrFinalized *big.Int) *AccountAsset { +func ConstructAccountAsset(assetId int64, balance *big.Int, offerCanceledOrFinalized *big.Int) *AccountAsset { return &AccountAsset{ assetId, balance, - lpAmount, offerCanceledOrFinalized, } } @@ -79,10 +75,9 @@ type AccountInfo struct { L1Address string Nonce int64 CollectionNonce int64 - // map[int64]*AccountAsset - AssetInfo map[int64]*AccountAsset // key: index, value: balance - AssetRoot string - Status int + AssetInfo map[int64]*AccountAsset // key: index, value: balance + AssetRoot string + Status int } func (ai *AccountInfo) DeepCopy() (*AccountInfo, error) { diff --git a/types/code.go b/types/code.go index b7d81cc02..b4d89b837 100644 --- a/types/code.go +++ b/types/code.go @@ -11,35 +11,32 @@ import ( // does not use the codes. We can leave the codes for future enhancement. var ( - DbErrNotFound = sqlx.ErrNotFound - DbErrSqlOperation = errors.New("unknown sql operation error") - DbErrFailToCreateBlock = errors.New("fail to create block") - DbErrFailToUpdateBlock = errors.New("fail to update block") - DbErrFailToUpdateTx = errors.New("fail to update tx") - DbErrFailToCreateCompressedBlock = errors.New("fail to create compressed block") - DbErrFailToCreateProof = errors.New("fail to create proof") - DbErrFailToUpdateProof = errors.New("fail to update proof") - DbErrFailToCreateSysConfig = errors.New("fail to create system config") - DbErrFailToUpdateSysConfig = errors.New("fail to update system config") - DbErrFailToCreateAsset = errors.New("fail to create asset") - DbErrFailToUpdateAsset = errors.New("fail to update asset") - DbErrFailToCreateAccount = errors.New("fail to create account") - DbErrFailToUpdateAccount = errors.New("fail to update account") - DbErrFailToCreateAccountHistory = errors.New("fail to create account history") - DbErrFailToCreateL1RollupTx = errors.New("fail to create l1 rollup tx") - DbErrFailToDeleteL1RollupTx = errors.New("fail to delete l1 rollup tx") - DbErrFailToL1SyncedBlock = errors.New("fail to create l1 synced block") - DbErrFailToCreateLiquidity = errors.New("fail to create liquidity") - DbErrFailToUpdateLiquidity = errors.New("fail to update liquidity") - DbErrFailToCreateLiquidityHistory = errors.New("fail to create liquidity history") - DbErrFailToCreatePoolTx = errors.New("fail to create pool tx") - DbErrFailToUpdatePoolTx = errors.New("fail to update pool tx") - DbErrFailToDeletePoolTx = errors.New("fail to delete pool tx") - DbErrFailToCreateNft = errors.New("fail to create nft") - DbErrFailToUpdateNft = errors.New("fail to update nft") - DbErrFailToCreateNftHistory = errors.New("fail to create nft history") - DbErrFailToCreatePriorityRequest = errors.New("fail to create priority request") - DbErrFailToUpdatePriorityRequest = errors.New("fail to update priority request") + DbErrNotFound = sqlx.ErrNotFound + DbErrSqlOperation = errors.New("unknown sql operation error") + DbErrFailToCreateBlock = errors.New("fail to create block") + DbErrFailToUpdateBlock = errors.New("fail to update block") + DbErrFailToUpdateTx = errors.New("fail to update tx") + DbErrFailToCreateCompressedBlock = errors.New("fail to create compressed block") + DbErrFailToCreateProof = errors.New("fail to create proof") + DbErrFailToUpdateProof = errors.New("fail to update proof") + DbErrFailToCreateSysConfig = errors.New("fail to create system config") + DbErrFailToUpdateSysConfig = errors.New("fail to update system config") + DbErrFailToCreateAsset = errors.New("fail to create asset") + DbErrFailToUpdateAsset = errors.New("fail to update asset") + DbErrFailToCreateAccount = errors.New("fail to create account") + DbErrFailToUpdateAccount = errors.New("fail to update account") + DbErrFailToCreateAccountHistory = errors.New("fail to create account history") + DbErrFailToCreateL1RollupTx = errors.New("fail to create l1 rollup tx") + DbErrFailToDeleteL1RollupTx = errors.New("fail to delete l1 rollup tx") + DbErrFailToL1SyncedBlock = errors.New("fail to create l1 synced block") + DbErrFailToCreatePoolTx = errors.New("fail to create pool tx") + DbErrFailToUpdatePoolTx = errors.New("fail to update pool tx") + DbErrFailToDeletePoolTx = errors.New("fail to delete pool tx") + DbErrFailToCreateNft = errors.New("fail to create nft") + DbErrFailToUpdateNft = errors.New("fail to update nft") + DbErrFailToCreateNftHistory = errors.New("fail to create nft history") + DbErrFailToCreatePriorityRequest = errors.New("fail to create priority request") + DbErrFailToUpdatePriorityRequest = errors.New("fail to update priority request") JsonErrUnmarshal = errors.New("json.Unmarshal err") JsonErrMarshal = errors.New("json.Marshal err") diff --git a/types/constant.go b/types/constant.go index 92ef0863c..7254c87bb 100644 --- a/types/constant.go +++ b/types/constant.go @@ -35,7 +35,6 @@ const ( EmptyCreatorTreasuryRate = 0 NilAccountName = "" - NilPairIndex = -1 NilNftIndex = int64(-1) NilAccountIndex = int64(-1) NilBlockHeight = -1 @@ -46,8 +45,7 @@ const ( NilExpiredAt = math.MaxInt64 NilAssetAmount = "0" - BNBAssetId = 0 - BNBDecimals = "1000000000000000000" + BNBAssetId = 0 ) var ( diff --git a/types/liquidity.go b/types/liquidity.go deleted file mode 100644 index 3b8e5657b..000000000 --- a/types/liquidity.go +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright © 2021 ZkBNB Protocol - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package types - -import ( - "encoding/json" - "errors" - "math/big" -) - -type LiquidityInfo struct { - PairIndex int64 - AssetAId int64 - AssetA *big.Int - AssetBId int64 - AssetB *big.Int - LpAmount *big.Int - KLast *big.Int - FeeRate int64 - TreasuryAccountIndex int64 - TreasuryRate int64 -} - -func (info *LiquidityInfo) String() string { - infoBytes, _ := json.Marshal(info) - return string(infoBytes) -} - -func EmptyLiquidityInfo(pairIndex int64) (info *LiquidityInfo) { - return &LiquidityInfo{ - PairIndex: pairIndex, - AssetAId: 0, - AssetA: ZeroBigInt, - AssetBId: 0, - AssetB: ZeroBigInt, - LpAmount: ZeroBigInt, - KLast: ZeroBigInt, - FeeRate: 0, - TreasuryAccountIndex: 0, - TreasuryRate: 0, - } -} - -func ConstructLiquidityInfo(pairIndex int64, assetAId int64, assetAAmount string, assetBId int64, assetBAmount string, - lpAmount string, kLast string, feeRate int64, treasuryAccountIndex int64, treasuryRate int64) (info *LiquidityInfo, err error) { - assetA, isValid := new(big.Int).SetString(assetAAmount, 10) - if !isValid { - return nil, errors.New("[ConstructLiquidityInfo] invalid bit int") - } - assetB, isValid := new(big.Int).SetString(assetBAmount, 10) - if !isValid { - return nil, errors.New("[ConstructLiquidityInfo] invalid bit int") - } - lp, isValid := new(big.Int).SetString(lpAmount, 10) - if !isValid { - return nil, errors.New("[ConstructLiquidityInfo] invalid bit int") - } - kLastInt, isValid := new(big.Int).SetString(kLast, 10) - if !isValid { - return nil, errors.New("[ConstructLiquidityInfo] invalid bit int") - } - info = &LiquidityInfo{ - PairIndex: pairIndex, - AssetAId: assetAId, - AssetA: assetA, - AssetBId: assetBId, - AssetB: assetB, - LpAmount: lp, - KLast: kLastInt, - FeeRate: feeRate, - TreasuryAccountIndex: treasuryAccountIndex, - TreasuryRate: treasuryRate, - } - return info, nil -} - -func ParseLiquidityInfo(infoStr string) (info *LiquidityInfo, err error) { - err = json.Unmarshal([]byte(infoStr), &info) - if err != nil { - return nil, JsonErrUnmarshal - } - return info, nil -} diff --git a/types/system.go b/types/system.go index bfb96b191..450aa135f 100644 --- a/types/system.go +++ b/types/system.go @@ -39,6 +39,5 @@ const ( ) var ( - ZeroBigInt = big.NewInt(0) - ZeroBigIntString = "0" + ZeroBigInt = big.NewInt(0) ) diff --git a/types/tx.go b/types/tx.go index ff299212e..41b290c69 100644 --- a/types/tx.go +++ b/types/tx.go @@ -20,21 +20,15 @@ package types import ( "encoding/json" - "github.com/bnb-chain/zkbnb-crypto/circuit" "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" ) const ( TxTypeEmpty = iota TxTypeRegisterZns - TxTypeCreatePair - TxTypeUpdatePairRate TxTypeDeposit TxTypeDepositNft TxTypeTransfer - TxTypeSwap - TxTypeAddLiquidity - TxTypeRemoveLiquidity TxTypeWithdraw TxTypeCreateCollection TxTypeMintNft @@ -49,9 +43,6 @@ const ( func IsL2Tx(txType int64) bool { if txType == TxTypeTransfer || - txType == TxTypeSwap || - txType == TxTypeAddLiquidity || - txType == TxTypeRemoveLiquidity || txType == TxTypeWithdraw || txType == TxTypeCreateCollection || txType == TxTypeMintNft || @@ -73,7 +64,6 @@ const ( AccountNameHashBytesSize = 32 PubkeyBytesSize = 32 AssetIdBytesSize = 2 - PairIndexBytesSize = 2 StateAmountBytesSize = 16 NftIndexBytesSize = 5 NftTokenIdBytesSize = 32 @@ -83,10 +73,6 @@ const ( RegisterZnsPubDataSize = TxTypeBytesSize + AccountIndexBytesSize + AccountNameBytesSize + AccountNameHashBytesSize + PubkeyBytesSize + PubkeyBytesSize - CreatePairPubDataSize = TxTypeBytesSize + PairIndexBytesSize + - AssetIdBytesSize + AssetIdBytesSize + FeeRateBytesSize + AccountIndexBytesSize + FeeRateBytesSize - UpdatePairRatePubdataSize = TxTypeBytesSize + PairIndexBytesSize + - FeeRateBytesSize + AccountIndexBytesSize + FeeRateBytesSize DepositPubDataSize = TxTypeBytesSize + AccountIndexBytesSize + AccountNameHashBytesSize + AssetIdBytesSize + StateAmountBytesSize DepositNftPubDataSize = TxTypeBytesSize + IsNewNftSize + AccountIndexBytesSize + NftIndexBytesSize + AddressBytesSize + @@ -106,14 +92,12 @@ const ( TypeAccountName TypeAccountNameOmitSpace TypeAccountPk - TypePairIndex TypeLimit TypeOffset TypeHash TypeBlockHeight TypeTxType TypeChainId - TypeLPAmount TypeAssetAmount TypeBoolean TypeGasFee @@ -121,7 +105,6 @@ const ( const ( AddressSize = 20 - FeeRateBase = circuit.RateBase EmptyStringKeccak = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" ) @@ -133,22 +116,6 @@ func ParseRegisterZnsTxInfo(txInfoStr string) (txInfo *txtypes.RegisterZnsTxInfo return txInfo, nil } -func ParseCreatePairTxInfo(txInfoStr string) (txInfo *txtypes.CreatePairTxInfo, err error) { - err = json.Unmarshal([]byte(txInfoStr), &txInfo) - if err != nil { - return nil, err - } - return txInfo, nil -} - -func ParseUpdatePairRateTxInfo(txInfoStr string) (txInfo *txtypes.UpdatePairRateTxInfo, err error) { - err = json.Unmarshal([]byte(txInfoStr), &txInfo) - if err != nil { - return nil, err - } - return txInfo, nil -} - func ParseDepositTxInfo(txInfoStr string) (txInfo *txtypes.DepositTxInfo, err error) { err = json.Unmarshal([]byte(txInfoStr), &txInfo) if err != nil { @@ -197,30 +164,6 @@ func ParseTransferTxInfo(txInfoStr string) (txInfo *txtypes.TransferTxInfo, err return txInfo, nil } -func ParseSwapTxInfo(txInfoStr string) (txInfo *txtypes.SwapTxInfo, err error) { - err = json.Unmarshal([]byte(txInfoStr), &txInfo) - if err != nil { - return nil, err - } - return txInfo, nil -} - -func ParseAddLiquidityTxInfo(txInfoStr string) (txInfo *txtypes.AddLiquidityTxInfo, err error) { - err = json.Unmarshal([]byte(txInfoStr), &txInfo) - if err != nil { - return nil, err - } - return txInfo, nil -} - -func ParseRemoveLiquidityTxInfo(txInfoStr string) (txInfo *txtypes.RemoveLiquidityTxInfo, err error) { - err = json.Unmarshal([]byte(txInfoStr), &txInfo) - if err != nil { - return nil, err - } - return txInfo, nil -} - func ParseMintNftTxInfo(txInfoStr string) (txInfo *txtypes.MintNftTxInfo, err error) { err = json.Unmarshal([]byte(txInfoStr), &txInfo) if err != nil { From c58af9319d0d8a94e65dbdc5f6ff887e979e413f Mon Sep 17 00:00:00 2001 From: Ethan Date: Thu, 29 Sep 2022 16:09:58 +0800 Subject: [PATCH 08/23] feat(api.server): add `Size` member to `Block struct` for fullnode (#209) * feat: add block Size for api server * chores: modify api reference doc Co-authored-by: cosinlink --- docs/api_reference.md | 1 + service/apiserver/internal/logic/block/getblocklogic.go | 1 + service/apiserver/internal/logic/block/getblockslogic.go | 1 + service/apiserver/server.api | 1 + service/apiserver/test/getblock_test.go | 1 + service/apiserver/test/getblocks_test.go | 1 + 6 files changed, 6 insertions(+) diff --git a/docs/api_reference.md b/docs/api_reference.md index ecd4c0356..a5b3340e5 100644 --- a/docs/api_reference.md +++ b/docs/api_reference.md @@ -509,6 +509,7 @@ Send raw transaction | verified_at | long | | Yes | | txs | [ [Tx](#tx) ] | | Yes | | status | long | | Yes | +| size | long | | Yes | #### Blocks diff --git a/service/apiserver/internal/logic/block/getblocklogic.go b/service/apiserver/internal/logic/block/getblocklogic.go index 1fae671a9..8b53238f8 100644 --- a/service/apiserver/internal/logic/block/getblocklogic.go +++ b/service/apiserver/internal/logic/block/getblocklogic.go @@ -71,6 +71,7 @@ func (l *GetBlockLogic) GetBlock(req *types.ReqGetBlock) (resp *types.Block, err VerifiedTxHash: block.VerifiedTxHash, VerifiedAt: block.VerifiedAt, Status: block.BlockStatus, + Size: block.BlockSize, } for _, dbTx := range block.Txs { tx := utils.ConvertTx(dbTx) diff --git a/service/apiserver/internal/logic/block/getblockslogic.go b/service/apiserver/internal/logic/block/getblockslogic.go index 801aa6aa4..0315806b5 100644 --- a/service/apiserver/internal/logic/block/getblockslogic.go +++ b/service/apiserver/internal/logic/block/getblockslogic.go @@ -62,6 +62,7 @@ func (l *GetBlocksLogic) GetBlocks(req *types.ReqGetRange) (*types.Blocks, error VerifiedTxHash: b.VerifiedTxHash, VerifiedAt: b.VerifiedAt, Status: b.BlockStatus, + Size: b.BlockSize, } for _, dbTx := range b.Txs { tx := utils.ConvertTx(dbTx) diff --git a/service/apiserver/server.api b/service/apiserver/server.api index a2b0e5bef..e785d6b2a 100644 --- a/service/apiserver/server.api +++ b/service/apiserver/server.api @@ -138,6 +138,7 @@ type ( VerifiedAt int64 `json:"verified_at"` Txs []*Tx `json:"txs"` Status int64 `json:"status"` + Size uint16 `json:"size"` } Blocks { diff --git a/service/apiserver/test/getblock_test.go b/service/apiserver/test/getblock_test.go index d60ee4739..b68610599 100644 --- a/service/apiserver/test/getblock_test.go +++ b/service/apiserver/test/getblock_test.go @@ -36,6 +36,7 @@ func (s *ApiServerSuite) TestGetBlock() { assert.NotNil(t, result.Height) assert.NotNil(t, result.Commitment) assert.NotNil(t, result.Status) + assert.NotNil(t, result.Size) assert.NotNil(t, result.StateRoot) fmt.Printf("result: %+v \n", result) } diff --git a/service/apiserver/test/getblocks_test.go b/service/apiserver/test/getblocks_test.go index e76a3a2d7..053c315d2 100644 --- a/service/apiserver/test/getblocks_test.go +++ b/service/apiserver/test/getblocks_test.go @@ -38,6 +38,7 @@ func (s *ApiServerSuite) TestGetBlocks() { assert.NotNil(t, result.Blocks[0].Height) assert.NotNil(t, result.Blocks[0].Commitment) assert.NotNil(t, result.Blocks[0].Status) + assert.NotNil(t, result.Blocks[0].Size) assert.NotNil(t, result.Blocks[0].StateRoot) //assert.NotNil(t, result.Blocks[0].Txs) } From c840eef3698efabb4df1ddb0dd1412e70cda6e1f Mon Sep 17 00:00:00 2001 From: WayToFuture Date: Thu, 29 Sep 2022 22:22:20 +0800 Subject: [PATCH 09/23] feat: add icon url for assets (#210) --- docs/api_reference.md | 13 +++++++------ .../apiserver/internal/logic/asset/getassetlogic.go | 5 +++++ .../internal/logic/asset/getassetslogic.go | 3 +++ service/apiserver/server.api | 1 + 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/api_reference.md b/docs/api_reference.md index a5b3340e5..5c22e2419 100644 --- a/docs/api_reference.md +++ b/docs/api_reference.md @@ -476,15 +476,16 @@ Send raw transaction #### Asset -| Name | Type | Description | Required | -|--------------| ---- | ----------- | -------- | +| Name | Type | Description | Required | +|--------------|---------| ----------- | -------- | | id | integer | | Yes | -| name | string | | Yes | +| name | string | | Yes | | decimals | integer | | Yes | -| symbol | string | | Yes | -| address | string | | Yes | -| price | string | | Yes | +| symbol | string | | Yes | +| address | string | | Yes | +| price | string | | Yes | | is_gas_asset | integer | | Yes | +| icon | string | | Yes | #### Assets diff --git a/service/apiserver/internal/logic/asset/getassetlogic.go b/service/apiserver/internal/logic/asset/getassetlogic.go index d788f7bca..b903860d3 100644 --- a/service/apiserver/internal/logic/asset/getassetlogic.go +++ b/service/apiserver/internal/logic/asset/getassetlogic.go @@ -2,6 +2,7 @@ package asset import ( "context" + "fmt" "strconv" "strings" @@ -15,6 +16,9 @@ import ( const ( queryById = "id" queryBySymbol = "symbol" + + // iconBaseUrl is used for showing icons for assets, asset owners should upload png files to the github repo + iconBaseUrl = "https://raw.githubusercontent.com/binance-chain/tokens-info/master/tokens/%s/%s.png" ) type GetAssetLogic struct { @@ -74,6 +78,7 @@ func (l *GetAssetLogic) GetAsset(req *types.ReqGetAsset) (resp *types.Asset, err Address: asset.L1Address, Price: strconv.FormatFloat(assetPrice, 'E', -1, 64), IsGasAsset: asset.IsGasAsset, + Icon: fmt.Sprintf(iconBaseUrl, strings.ToLower(asset.AssetSymbol), strings.ToLower(asset.AssetSymbol)), } return resp, nil } diff --git a/service/apiserver/internal/logic/asset/getassetslogic.go b/service/apiserver/internal/logic/asset/getassetslogic.go index 7a284ae0f..461f13b75 100644 --- a/service/apiserver/internal/logic/asset/getassetslogic.go +++ b/service/apiserver/internal/logic/asset/getassetslogic.go @@ -2,7 +2,9 @@ package asset import ( "context" + "fmt" "strconv" + "strings" "github.com/zeromicro/go-zero/core/logx" @@ -60,6 +62,7 @@ func (l *GetAssetsLogic) GetAssets(req *types.ReqGetRange) (resp *types.Assets, Address: asset.L1Address, Price: strconv.FormatFloat(assetPrice, 'E', -1, 64), IsGasAsset: asset.IsGasAsset, + Icon: fmt.Sprintf(iconBaseUrl, strings.ToLower(asset.AssetSymbol), strings.ToLower(asset.AssetSymbol)), }) } return resp, nil diff --git a/service/apiserver/server.api b/service/apiserver/server.api index e785d6b2a..b854e7e00 100644 --- a/service/apiserver/server.api +++ b/service/apiserver/server.api @@ -93,6 +93,7 @@ type ( Address string `json:"address"` Price string `json:"price"` IsGasAsset uint32 `json:"is_gas_asset"` + Icon string `json:"icon"` } Assets { From 885f6f952182f194802bbcbcfa5c797820fa4a4f Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Fri, 30 Sep 2022 09:47:06 +0800 Subject: [PATCH 10/23] committer: add priority operation metric and check the logic of request operation order (#200) Co-authored-by: carlcarl --- core/statedb/chaindb.go | 3 + dao/priorityrequest/priority_request.go | 36 ++++++--- dao/tx/tx_pool.go | 13 +++ service/committer/committer/committer.go | 79 +++++++++++++++++++ service/monitor/monitor/monitor.go | 24 ++++++ .../monitor/monitor_priority_requests.go | 10 ++- types/tx.go | 11 +++ 7 files changed, 166 insertions(+), 10 deletions(-) diff --git a/core/statedb/chaindb.go b/core/statedb/chaindb.go index 4ad7e512a..8788ae271 100644 --- a/core/statedb/chaindb.go +++ b/core/statedb/chaindb.go @@ -9,6 +9,7 @@ import ( "github.com/bnb-chain/zkbnb/dao/block" "github.com/bnb-chain/zkbnb/dao/compressedblock" "github.com/bnb-chain/zkbnb/dao/nft" + "github.com/bnb-chain/zkbnb/dao/priorityrequest" "github.com/bnb-chain/zkbnb/dao/sysconfig" "github.com/bnb-chain/zkbnb/dao/tx" ) @@ -19,6 +20,7 @@ type ChainDB struct { BlockModel block.BlockModel CompressedBlockModel compressedblock.CompressedBlockModel TxModel tx.TxModel + PriorityRequestModel priorityrequest.PriorityRequestModel // State DB AccountModel account.AccountModel @@ -38,6 +40,7 @@ func NewChainDB(db *gorm.DB) *ChainDB { BlockModel: block.NewBlockModel(db), CompressedBlockModel: compressedblock.NewCompressedBlockModel(db), TxModel: tx.NewTxModel(db), + PriorityRequestModel: priorityrequest.NewPriorityRequestModel(db), AccountModel: account.NewAccountModel(db), AccountHistoryModel: account.NewAccountHistoryModel(db), diff --git a/dao/priorityrequest/priority_request.go b/dao/priorityrequest/priority_request.go index 37c1bb7ef..e9b36fd26 100644 --- a/dao/priorityrequest/priority_request.go +++ b/dao/priorityrequest/priority_request.go @@ -38,6 +38,7 @@ type ( GetLatestHandledRequestId() (requestId int64, err error) UpdateHandledPriorityRequestsInTransact(tx *gorm.DB, requests []*PriorityRequest) (err error) CreatePriorityRequestsInTransact(tx *gorm.DB, requests []*PriorityRequest) (err error) + GetPriorityRequestsByL2TxHash(txHash string) (tx *PriorityRequest, err error) } defaultPriorityRequestModel struct { @@ -63,6 +64,8 @@ type ( ExpirationBlock int64 // status Status int + // L2TxHash for the relation to tx table + L2TxHash string `gorm:"index"` } ) @@ -119,16 +122,19 @@ func (m *defaultPriorityRequestModel) GetLatestHandledRequestId() (requestId int } func (m *defaultPriorityRequestModel) UpdateHandledPriorityRequestsInTransact(tx *gorm.DB, requests []*PriorityRequest) (err error) { - ids := make([]uint, 0, len(requests)) for _, request := range requests { - ids = append(ids, request.ID) - } - dbTx := tx.Table(m.table).Where("id in ?", ids).Update("status", HandledStatus) - if dbTx.Error != nil { - return dbTx.Error - } - if dbTx.RowsAffected != int64(len(ids)) { - return types.DbErrFailToUpdatePriorityRequest + dbTx := tx.Table(m.table).Where("id = ?", request.ID).Updates( + map[string]interface{}{ + "status": HandledStatus, + "l2_tx_hash": request.L2TxHash, + }, + ) + if dbTx.Error != nil { + return dbTx.Error + } + if dbTx.RowsAffected != 1 { + return types.DbErrFailToUpdatePriorityRequest + } } return nil } @@ -143,3 +149,15 @@ func (m *defaultPriorityRequestModel) CreatePriorityRequestsInTransact(tx *gorm. } return nil } + +func (m *defaultPriorityRequestModel) GetPriorityRequestsByL2TxHash(txHash string) (tx *PriorityRequest, err error) { + dbTx := m.DB.Table(m.table).Where("l2_tx_hash = ?", txHash).Limit(1).Find(&tx) + if dbTx.Error != nil { + return nil, types.DbErrSqlOperation + } + if dbTx.RowsAffected == 0 { + return nil, types.DbErrNotFound + } + + return tx, nil +} diff --git a/dao/tx/tx_pool.go b/dao/tx/tx_pool.go index 986751911..8d8866a6c 100644 --- a/dao/tx/tx_pool.go +++ b/dao/tx/tx_pool.go @@ -41,6 +41,7 @@ type ( CreateTxsInTransact(tx *gorm.DB, txs []*Tx) error UpdateTxsInTransact(tx *gorm.DB, txs []*Tx) error DeleteTxsInTransact(tx *gorm.DB, txs []*Tx) error + GetLatestTx(txTypes []int64, statuses []int) (tx *Tx, err error) } defaultTxPoolModel struct { @@ -184,3 +185,15 @@ func (m *defaultTxPoolModel) DeleteTxsInTransact(tx *gorm.DB, txs []*Tx) error { } return nil } + +func (m *defaultTxPoolModel) GetLatestTx(txTypes []int64, statuses []int) (tx *Tx, err error) { + + dbTx := m.DB.Table(m.table).Where("tx_status IN ? AND tx_type IN ?", statuses, txTypes).Order("id DESC").Limit(1).Find(&tx) + if dbTx.Error != nil { + return nil, types.DbErrSqlOperation + } else if dbTx.RowsAffected == 0 { + return nil, types.DbErrNotFound + } + + return tx, nil +} diff --git a/service/committer/committer/committer.go b/service/committer/committer/committer.go index d327c6f50..d3027e31f 100644 --- a/service/committer/committer/committer.go +++ b/service/committer/committer/committer.go @@ -5,18 +5,33 @@ import ( "fmt" "time" + "github.com/prometheus/client_golang/prometheus" "github.com/zeromicro/go-zero/core/logx" "gorm.io/gorm" "github.com/bnb-chain/zkbnb/core" "github.com/bnb-chain/zkbnb/dao/block" "github.com/bnb-chain/zkbnb/dao/tx" + "github.com/bnb-chain/zkbnb/types" ) const ( MaxCommitterInterval = 60 * 1 ) +var ( + priorityOperationMetric = prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "zkbnb", + Name: "prioriry_operation_process", + Help: "Priority operation requestID metrics.", + }) + priorityOperationHeightMetric = prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "zkbnb", + Name: "prioriry_operation_process_height", + Help: "Priority operation height metrics.", + }) +) + type Config struct { core.ChainConfig @@ -45,6 +60,13 @@ func NewCommitter(config *Config) (*Committer, error) { return nil, fmt.Errorf("new blockchain error: %v", err) } + if err := prometheus.Register(priorityOperationMetric); err != nil { + return nil, fmt.Errorf("prometheus.Register priorityOperationMetric error: %v", err) + } + if err := prometheus.Register(priorityOperationHeightMetric); err != nil { + return nil, fmt.Errorf("prometheus.Register priorityOperationHeightMetric error: %v", err) + } + committer := &Committer{ running: true, config: config, @@ -62,6 +84,12 @@ func (c *Committer) Run() { panic("restore executed tx failed: " + err.Error()) } + latestRequestId, err := c.getLatestExecutedRequestId() + if err != nil { + logx.Error("get latest executed request ID failed:", err) + latestRequestId = -1 + } + for { if !c.running { break @@ -108,6 +136,23 @@ func (c *Committer) Run() { continue } + if types.IsPriorityOperationTx(poolTx.TxType) { + request, err := c.bc.PriorityRequestModel.GetPriorityRequestsByL2TxHash(poolTx.TxHash) + if err == nil { + + priorityOperationMetric.Set(float64(request.RequestId)) + priorityOperationHeightMetric.Set(float64(request.L1BlockHeight)) + + if latestRequestId != -1 && request.RequestId != latestRequestId+1 { + logx.Errorf("invalid request ID: %d, txHash: %s", request.RequestId, poolTx.TxHash) + return + } + latestRequestId = request.RequestId + } else { + logx.Errorf("query txHash: %s in PriorityRequestTable failed, err %v ", poolTx.TxHash, err) + } + } + // Write the proposed block into database when the first transaction executed. if len(c.bc.Statedb.Txs) == 1 { err = c.createNewBlock(curBlock, poolTx) @@ -293,3 +338,37 @@ func (c *Committer) computeCurrentBlockSize() int { } return blockSize } + +func (c *Committer) getLatestExecutedRequestId() (int64, error) { + + statuses := []int{ + tx.StatusExecuted, + tx.StatusPacked, + tx.StatusCommitted, + tx.StatusVerified, + } + + txTypes := []int64{ + types.TxTypeRegisterZns, + types.TxTypeDeposit, + types.TxTypeDepositNft, + types.TxTypeFullExit, + types.TxTypeFullExitNft, + } + + latestTx, err := c.bc.TxPoolModel.GetLatestTx(txTypes, statuses) + if err != nil && err != types.DbErrNotFound { + logx.Errorf("get latest executed tx failed: %v", err) + return -1, err + } else if err == types.DbErrNotFound { + return -1, nil + } + + p, err := c.bc.PriorityRequestModel.GetPriorityRequestsByL2TxHash(latestTx.TxHash) + if err != nil { + logx.Errorf("get priority request by txhash: %s failed: %v", latestTx.TxHash, err) + return -1, err + } + + return p.RequestId, nil +} diff --git a/service/monitor/monitor/monitor.go b/service/monitor/monitor/monitor.go index 91223e14b..65152f86c 100644 --- a/service/monitor/monitor/monitor.go +++ b/service/monitor/monitor/monitor.go @@ -19,6 +19,7 @@ package monitor import ( "fmt" + "github.com/prometheus/client_golang/prometheus" "github.com/zeromicro/go-zero/core/logx" "gorm.io/driver/postgres" "gorm.io/gorm" @@ -36,6 +37,20 @@ import ( "github.com/bnb-chain/zkbnb/types" ) +var ( + priorityOperationMetric = prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "zkbnb", + Name: "prioriry_operation_insert", + Help: "Priority operation requestID metrics.", + }) + + priorityOperationHeightMetric = prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "zkbnb", + Name: "prioriry_operation_insert_height", + Help: "Priority operation height metrics.", + }) +) + type Monitor struct { Config config.Config @@ -104,6 +119,15 @@ func NewMonitor(c config.Config) *Monitor { monitor.governanceContractAddress = governanceAddressConfig.Value monitor.cli = bscRpcCli + if err := prometheus.Register(priorityOperationMetric); err != nil { + logx.Severef("fatal error, cannot register prometheus, err: %s", err.Error()) + panic(err) + } + if err := prometheus.Register(priorityOperationHeightMetric); err != nil { + logx.Severef("fatal error, cannot register prometheus, err: %s", err.Error()) + panic(err) + } + return monitor } diff --git a/service/monitor/monitor/monitor_priority_requests.go b/service/monitor/monitor/monitor_priority_requests.go index 207784f8b..d1d8aef80 100644 --- a/service/monitor/monitor/monitor_priority_requests.go +++ b/service/monitor/monitor/monitor_priority_requests.go @@ -73,6 +73,9 @@ func (m *Monitor) MonitorPriorityRequests() error { BlockHeight: types.NilBlockHeight, TxStatus: tx.StatusPending, } + + request.L2TxHash = txHash + // handle request based on request type var txInfoBytes []byte switch request.TxType { @@ -158,11 +161,16 @@ func (m *Monitor) MonitorPriorityRequests() error { if err != nil { return err } - return nil }) if err != nil { return fmt.Errorf("unable to create pool tx and update priority requests, error: %v", err) } + + for _, request := range pendingRequests { + priorityOperationMetric.Set(float64(request.RequestId)) + priorityOperationHeightMetric.Set(float64(request.L1BlockHeight)) + } + return nil } diff --git a/types/tx.go b/types/tx.go index 41b290c69..f4134490d 100644 --- a/types/tx.go +++ b/types/tx.go @@ -55,6 +55,17 @@ func IsL2Tx(txType int64) bool { return false } +func IsPriorityOperationTx(txType int64) bool { + if txType == TxTypeRegisterZns || + txType == TxTypeDeposit || + txType == TxTypeDepositNft || + txType == TxTypeFullExit || + txType == TxTypeFullExitNft { + return true + } + return false +} + const ( TxTypeBytesSize = 1 IsNewNftSize = 1 From 456637a9d11f626c53a7d5193bd427a95cada78e Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Fri, 30 Sep 2022 10:47:20 +0800 Subject: [PATCH 11/23] fix deploy local script (#208) * fix deploy local script * fix comments Co-authored-by: Keefe Liu --- deploy-local.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/deploy-local.sh b/deploy-local.sh index 22a467e13..6d522285c 100644 --- a/deploy-local.sh +++ b/deploy-local.sh @@ -11,6 +11,7 @@ DEPLOY_PATH=~/zkbnb-deploy KEY_PATH=~/.zkbnb ZkBNB_REPO_PATH=$(cd `dirname $0`; pwd) CMC_TOKEN=cfce503f-fake-fake-fake-bbab5257dac8 +BSC_TESTNET_PRIVATE_KEY=acbaa26******************************a88367d9 export PATH=$PATH:/usr/local/go/bin:/usr/local/go/bin:/root/go/bin echo '0. stop old database/redis and docker run new database/redis' @@ -59,7 +60,7 @@ echo 'latest block number = ' $blockNumber echo '4-2. deploy contracts, register and deposit on BSC Testnet' cd ${DEPLOY_PATH} -cd ./zkbnb-contract && yarn install +cd ./zkbnb-contract && echo "BSC_TESTNET_PRIVATE_KEY=${BSC_TESTNET_PRIVATE_KEY}" > .env && npm install npx hardhat --network BSCTestnet run ./scripts/deploy-keccak256/deploy.js echo 'Recorded latest contract addresses into ${DEPLOY_PATH}/zkbnb-contract/info/addresses.json' @@ -224,9 +225,10 @@ ChainConfig: #NetworkRPCSysConfigName: "LocalTestNetworkRpc" ConfirmBlocksCount: 0 MaxWaitingTime: 120 - MaxBlockCount: 4 - Sk: "acbaa269bd7573ff12361be4b97201aef019776ea13384681d4e5ba6a88367d9" - GasLimit: 5000000 + MaxBlockCount: 3 + Sk: "107f9d2a50ce2d8337e0c5220574e9fcf2bf60002da5acf07718f4d531ea3faa" + GasLimit: 20000000 + GasPrice: 0 TreeDB: Driver: memorydb From b063c9b564990f07033c5b4733420d53c1e2ca92 Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Fri, 30 Sep 2022 14:44:55 +0800 Subject: [PATCH 12/23] update zkbnb-crypto version (#212) --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2c0f42c48..5add302e5 100644 --- a/go.mod +++ b/go.mod @@ -87,7 +87,7 @@ require ( ) require ( - github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220928090246-9a20106a2347 + github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220929142710-f30d7d0a9428 github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f github.com/consensys/gnark v0.7.0 diff --git a/go.sum b/go.sum index 8652cbe7e..3a91c1811 100644 --- a/go.sum +++ b/go.sum @@ -119,6 +119,8 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220928090246-9a20106a2347 h1:Dv+ztM5Bb8I2m3cf5WDYZZ+sFmNhWzNS41cxAx2AUrc= github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220928090246-9a20106a2347/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220929142710-f30d7d0a9428 h1:tC1qPYsjy9KY0LoRuvnXyQI0RdyYWd5E5QyOGP5d35M= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220929142710-f30d7d0a9428/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 h1:1rMa8XpplDNZaxeM1ifXMjSSeH/ucJyLUjHHEw1z4AA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2/go.mod h1:T69T8enicQ5kSRPIzyPJv/jhuvRMz1UxsijPXmlis+I= github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f h1:zBVWOWlH4w18O6wp0gZML4U2n1rxsFLb7KB7DFE8zcQ= From 43535ae94ab54b957ae9a4ca2f82dd13ccd7fd57 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Tue, 4 Oct 2022 11:14:32 +0800 Subject: [PATCH 13/23] feat: Replace apiserver gocache with ristretto cache (#207) Co-authored-by: carlcarl --- deploy-local.sh | 2 + deployment/docker-compose/docker-compose.sh | 4 +- deployment/helm/local-value/values.yaml | 2 + deployment/helm/zkbnb/values.yaml | 2 + go.mod | 4 +- go.sum | 1 + service/apiserver/etc/server-api.yaml.example | 2 + service/apiserver/internal/cache/mem_cache.go | 62 ++++++++++++------- service/apiserver/internal/config/config.go | 4 ++ .../apiserver/internal/svc/servicecontext.go | 4 +- service/apiserver/test/suite_test.go | 4 +- 11 files changed, 62 insertions(+), 29 deletions(-) diff --git a/deploy-local.sh b/deploy-local.sh index 6d522285c..5f091d864 100644 --- a/deploy-local.sh +++ b/deploy-local.sh @@ -280,6 +280,8 @@ MemCache: BlockExpiration: 400 TxExpiration: 400 PriceExpiration: 3600000 + MaxCounterNum: 100000 + MaxKeyNum: 10000 " > ${DEPLOY_PATH}/zkbnb/service/apiserver/etc/config.yaml echo -e " diff --git a/deployment/docker-compose/docker-compose.sh b/deployment/docker-compose/docker-compose.sh index 0fc8c25bb..206050781 100644 --- a/deployment/docker-compose/docker-compose.sh +++ b/deployment/docker-compose/docker-compose.sh @@ -175,6 +175,8 @@ MemCache: BlockExpiration: 400 TxExpiration: 400 PriceExpiration: 3600000 + MaxCounterNum: 100000 + MaxKeyNum: 10000 " > ${CONFIG_PATH}/apiserver.yaml @@ -203,4 +205,4 @@ down) *) echo "Usage: docker-compose.sh up \$block_number | down" ;; -esac \ No newline at end of file +esac diff --git a/deployment/helm/local-value/values.yaml b/deployment/helm/local-value/values.yaml index 3180cd180..b3b948391 100644 --- a/deployment/helm/local-value/values.yaml +++ b/deployment/helm/local-value/values.yaml @@ -113,5 +113,7 @@ configs: BlockExpiration: 400 TxExpiration: 400 PriceExpiration: 3600000 + MaxCounterNum: 100000 + MaxKeyNum: 10000 logLevel: error diff --git a/deployment/helm/zkbnb/values.yaml b/deployment/helm/zkbnb/values.yaml index d2fd3d3c7..3e2c9573d 100644 --- a/deployment/helm/zkbnb/values.yaml +++ b/deployment/helm/zkbnb/values.yaml @@ -112,4 +112,6 @@ configs: BlockExpiration: 400 TxExpiration: 400 PriceExpiration: 3600000 + MaxCounterNum: 100000 + MaxKeyNum: 10000 logLevel: info diff --git a/go.mod b/go.mod index 5add302e5..e8062f5a1 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/bnb-chain/zkbnb go 1.17 require ( + github.com/dgraph-io/ristretto v0.1.0 github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/panjf2000/ants/v2 v2.5.0 github.com/zeromicro/go-zero v1.3.4 @@ -21,6 +22,7 @@ require ( github.com/deckarep/golang-set v1.8.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.0 // indirect github.com/fatih/color v1.13.0 // indirect github.com/fxamacker/cbor/v2 v2.2.0 // indirect github.com/go-logr/logr v1.2.3 // indirect @@ -29,6 +31,7 @@ require ( github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/golang-jwt/jwt/v4 v4.4.1 // indirect + github.com/golang/glog v1.0.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/gorilla/websocket v1.4.2 // indirect @@ -96,7 +99,6 @@ require ( github.com/ethereum/go-ethereum v1.10.23 github.com/go-redis/redis/v8 v8.11.5 github.com/google/uuid v1.3.0 // indirect - github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 github.com/robfig/cron/v3 v3.0.1 github.com/stretchr/testify v1.7.2 diff --git a/go.sum b/go.sum index 3a91c1811..d421d9adb 100644 --- a/go.sum +++ b/go.sum @@ -199,6 +199,7 @@ github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/Lu github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= diff --git a/service/apiserver/etc/server-api.yaml.example b/service/apiserver/etc/server-api.yaml.example index 0dc2a4eee..5686bb1ee 100644 --- a/service/apiserver/etc/server-api.yaml.example +++ b/service/apiserver/etc/server-api.yaml.example @@ -35,3 +35,5 @@ MemCache: BlockExpiration: 400 TxExpiration: 400 PriceExpiration: 3600000 + MaxCounterNum: 100000 + MaxKeyNum: 10000 diff --git a/service/apiserver/internal/cache/mem_cache.go b/service/apiserver/internal/cache/mem_cache.go index e8b780641..c5eb67d4f 100644 --- a/service/apiserver/internal/cache/mem_cache.go +++ b/service/apiserver/internal/cache/mem_cache.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - gocache "github.com/patrickmn/go-cache" + "github.com/dgraph-io/ristretto" accdao "github.com/bnb-chain/zkbnb/dao/account" assetdao "github.com/bnb-chain/zkbnb/dao/asset" @@ -14,8 +14,7 @@ import ( ) const ( - cacheDefaultExpiration = time.Hour * 1 //gocache default expiration - cacheDefaultPurgeInterval = time.Minute * 5 // gocache purge interval + cacheDefaultExpiration = time.Hour * 1 //gocache default expiration AccountIndexNameKeyPrefix = "in:" //key for cache: accountIndex -> accountName AccountIndexPkKeyPrefix = "ip:" //key for cache: accountIndex -> accountPk @@ -40,7 +39,7 @@ const ( type fallback func() (interface{}, error) type MemCache struct { - goCache *gocache.Cache + goCache *ristretto.Cache accountModel accdao.AccountModel assetModel assetdao.AssetModel accountExpiration time.Duration @@ -50,11 +49,26 @@ type MemCache struct { priceExpiration time.Duration } -func NewMemCache(accountModel accdao.AccountModel, assetModel assetdao.AssetModel, +func MustNewMemCache(accountModel accdao.AccountModel, assetModel assetdao.AssetModel, accountExpiration, blockExpiration, txExpiration, - assetExpiration, priceExpiration int) *MemCache { + assetExpiration, priceExpiration int, maxCounterNum, maxKeyNum int64) *MemCache { + + cache, err := ristretto.NewCache(&ristretto.Config{ + NumCounters: maxCounterNum, + MaxCost: maxKeyNum, + BufferItems: 64, // official recommended value + + // Called when setting cost to 0 in `Set/SetWithTTL` + Cost: func(value interface{}) int64 { + return 1 + }, + }) + if err != nil { + panic("MemCache init failed") + } + memCache := &MemCache{ - goCache: gocache.New(cacheDefaultExpiration, cacheDefaultPurgeInterval), + goCache: cache, accountModel: accountModel, assetModel: assetModel, accountExpiration: time.Duration(accountExpiration) * time.Millisecond, @@ -75,15 +89,15 @@ func (m *MemCache) getWithSet(key string, duration time.Duration, f fallback) (i if err != nil { return nil, err } - m.goCache.Set(key, result, duration) + m.goCache.SetWithTTL(key, result, 0, duration) return result, nil } func (m *MemCache) setAccount(accountIndex int64, accountName, accountPk string) { - m.goCache.Set(fmt.Sprintf("%s%d", AccountIndexNameKeyPrefix, accountIndex), accountName, gocache.DefaultExpiration) - m.goCache.Set(fmt.Sprintf("%s%d", AccountIndexPkKeyPrefix, accountIndex), accountPk, gocache.DefaultExpiration) - m.goCache.Set(fmt.Sprintf("%s%s", AccountNameKeyPrefix, accountName), accountIndex, gocache.DefaultExpiration) - m.goCache.Set(fmt.Sprintf("%s%s", AccountPkKeyPrefix, accountPk), accountIndex, gocache.DefaultExpiration) + m.goCache.SetWithTTL(fmt.Sprintf("%s%d", AccountIndexNameKeyPrefix, accountIndex), accountName, 0, cacheDefaultExpiration) + m.goCache.SetWithTTL(fmt.Sprintf("%s%d", AccountIndexPkKeyPrefix, accountIndex), accountPk, 0, cacheDefaultExpiration) + m.goCache.SetWithTTL(fmt.Sprintf("%s%s", AccountNameKeyPrefix, accountName), accountIndex, 0, cacheDefaultExpiration) + m.goCache.SetWithTTL(fmt.Sprintf("%s%s", AccountPkKeyPrefix, accountPk), accountIndex, 0, cacheDefaultExpiration) } func (m *MemCache) GetAccountIndexByName(accountName string) (int64, error) { @@ -167,7 +181,7 @@ func (m *MemCache) GetBlockByHeightWithFallback(blockHeight int64, f fallback) ( block := b.(*blockdao.Block) key = fmt.Sprintf("%s%s", BlockByCommitmentKeyPrefix, block.BlockCommitment) - m.goCache.Set(key, block, m.blockExpiration) + m.goCache.SetWithTTL(key, block, 0, m.blockExpiration) return block, nil } @@ -180,7 +194,7 @@ func (m *MemCache) GetBlockByCommitmentWithFallback(blockCommitment string, f fa block := b.(*blockdao.Block) key = fmt.Sprintf("%s%d", BlockByHeightKeyPrefix, block.BlockHeight) - m.goCache.Set(key, block, m.blockExpiration) + m.goCache.SetWithTTL(key, block, 0, m.blockExpiration) return block, nil } @@ -226,10 +240,10 @@ func (m *MemCache) GetAssetByIdWithFallback(assetId int64, f fallback) (*assetda asset := a.(*assetdao.Asset) key = fmt.Sprintf("%s%s", AssetBySymbolKeyPrefix, asset.AssetSymbol) - m.goCache.Set(key, asset, m.assetExpiration) + m.goCache.SetWithTTL(key, asset, 0, m.assetExpiration) key = fmt.Sprintf("%s%d", AssetIdNameKeyPrefix, assetId) - m.goCache.Set(key, asset.AssetName, gocache.DefaultExpiration) + m.goCache.SetWithTTL(key, asset.AssetName, 0, cacheDefaultExpiration) return asset, nil } @@ -242,10 +256,10 @@ func (m *MemCache) GetAssetBySymbolWithFallback(assetSymbol string, f fallback) asset := a.(*assetdao.Asset) key = fmt.Sprintf("%s%d", AssetByIdKeyPrefix, asset.AssetId) - m.goCache.Set(key, asset, m.assetExpiration) + m.goCache.SetWithTTL(key, asset, 0, m.assetExpiration) key = fmt.Sprintf("%s%d", AssetIdNameKeyPrefix, asset.AssetId) - m.goCache.Set(key, asset.AssetName, gocache.DefaultExpiration) + m.goCache.SetWithTTL(key, asset.AssetName, 0, cacheDefaultExpiration) return asset, nil } @@ -260,9 +274,9 @@ func (m *MemCache) GetAssetNameById(assetId int64) (string, error) { return "", err } - m.goCache.Set(keyForName, asset.AssetName, gocache.DefaultExpiration) + m.goCache.SetWithTTL(keyForName, asset.AssetName, 0, cacheDefaultExpiration) keyForSymbol := fmt.Sprintf("%s%d", AssetIdSymbolKeyPrefix, assetId) - m.goCache.Set(keyForSymbol, asset.AssetSymbol, gocache.DefaultExpiration) + m.goCache.SetWithTTL(keyForSymbol, asset.AssetSymbol, 0, cacheDefaultExpiration) return asset.AssetName, nil } @@ -278,9 +292,9 @@ func (m *MemCache) GetAssetSymbolById(assetId int64) (string, error) { return "", err } - m.goCache.Set(keyForSymbol, asset.AssetSymbol, gocache.DefaultExpiration) + m.goCache.SetWithTTL(keyForSymbol, asset.AssetSymbol, 0, cacheDefaultExpiration) keyForName := fmt.Sprintf("%s%d", AssetIdNameKeyPrefix, assetId) - m.goCache.Set(keyForName, asset.AssetName, gocache.DefaultExpiration) + m.goCache.SetWithTTL(keyForName, asset.AssetName, 0, cacheDefaultExpiration) return asset.AssetSymbol, nil } @@ -296,12 +310,12 @@ func (m *MemCache) GetPriceWithFallback(symbol string, f fallback) (float64, err func (m *MemCache) SetPrice(symbol string, price float64) { key := fmt.Sprintf("%s%s", PriceKeyPrefix, symbol) - m.goCache.Set(key, price, m.priceExpiration) + m.goCache.SetWithTTL(key, price, int64(len(key)), m.priceExpiration) } func (m *MemCache) GetSysConfigWithFallback(configName string, f fallback) (*sysconfig.SysConfig, error) { key := fmt.Sprintf("%s%s", SysConfigKeyPrefix, configName) - c, err := m.getWithSet(key, gocache.DefaultExpiration, f) + c, err := m.getWithSet(key, cacheDefaultExpiration, f) if err != nil { return nil, err } diff --git a/service/apiserver/internal/config/config.go b/service/apiserver/internal/config/config.go index 0a835870d..bcc6315ba 100644 --- a/service/apiserver/internal/config/config.go +++ b/service/apiserver/internal/config/config.go @@ -26,5 +26,9 @@ type Config struct { BlockExpiration int TxExpiration int PriceExpiration int + // Number of 4-bit access counters to keep for admission and eviction + // Setting this to 10x the number of items you expect to keep in the cache when full + MaxCounterNum int64 + MaxKeyNum int64 } } diff --git a/service/apiserver/internal/svc/servicecontext.go b/service/apiserver/internal/svc/servicecontext.go index b76242ff7..4f327d548 100644 --- a/service/apiserver/internal/svc/servicecontext.go +++ b/service/apiserver/internal/svc/servicecontext.go @@ -50,8 +50,8 @@ func NewServiceContext(c config.Config) *ServiceContext { accountModel := account.NewAccountModel(db) nftModel := nft.NewL2NftModel(db) assetModel := asset.NewAssetModel(db) - memCache := cache.NewMemCache(accountModel, assetModel, c.MemCache.AccountExpiration, c.MemCache.BlockExpiration, - c.MemCache.TxExpiration, c.MemCache.AssetExpiration, c.MemCache.PriceExpiration) + memCache := cache.MustNewMemCache(accountModel, assetModel, c.MemCache.AccountExpiration, c.MemCache.BlockExpiration, + c.MemCache.TxExpiration, c.MemCache.AssetExpiration, c.MemCache.PriceExpiration, c.MemCache.MaxCounterNum, c.MemCache.MaxKeyNum) return &ServiceContext{ Config: c, RedisCache: redisCache, diff --git a/service/apiserver/test/suite_test.go b/service/apiserver/test/suite_test.go index feb6397c8..8fc2673f4 100644 --- a/service/apiserver/test/suite_test.go +++ b/service/apiserver/test/suite_test.go @@ -78,7 +78,9 @@ func (s *ApiServerSuite) SetupSuite() { BlockExpiration int TxExpiration int PriceExpiration int - }{AccountExpiration: 10000, AssetExpiration: 10000, BlockExpiration: 10000, TxExpiration: 10000, PriceExpiration: 3600000}, + MaxCounterNum int64 + MaxKeyNum int64 + }{AccountExpiration: 10000, AssetExpiration: 10000, BlockExpiration: 10000, TxExpiration: 10000, PriceExpiration: 3600000, MaxCounterNum: 10000, MaxKeyNum: 10000}, } c.Postgres = struct{ DataSource string }{DataSource: "host=127.0.0.1 user=postgres password=ZkBNB@123 dbname=zkbnb port=5433 sslmode=disable"} c.CacheRedis = cache.CacheConf{} From c5a5f535127e3a237a79dff305402c7144087bf0 Mon Sep 17 00:00:00 2001 From: yutianwu Date: Sat, 8 Oct 2022 10:48:30 +0800 Subject: [PATCH 14/23] refactor: prohibit native l1 nft deposits (#213) * refactor: prohibit native l1 nft deposits * update dependency --- common/chain/pubdata_helper.go | 2 -- common/prove/deposit_nft.go | 1 - core/executor/deposit_nft_executor.go | 27 +++++---------------------- go.mod | 4 ++-- go.sum | 6 ++---- types/tx.go | 3 +-- 6 files changed, 10 insertions(+), 33 deletions(-) diff --git a/common/chain/pubdata_helper.go b/common/chain/pubdata_helper.go index fa2fb8dc9..659bedc70 100644 --- a/common/chain/pubdata_helper.go +++ b/common/chain/pubdata_helper.go @@ -96,7 +96,6 @@ func ParseDepositNftPubData(pubData []byte) (tx *txtypes.DepositNftTxInfo, err e } offset := 0 offset, txType := common2.ReadUint8(pubData, offset) - offset, isNewNft := common2.ReadUint8(pubData, offset) offset, accountIndex := common2.ReadUint32(pubData, offset) offset, nftIndex := common2.ReadUint40(pubData, offset) offset, nftL1Address := common2.ReadAddress(pubData, offset) @@ -108,7 +107,6 @@ func ParseDepositNftPubData(pubData []byte) (tx *txtypes.DepositNftTxInfo, err e _, collectionId := common2.ReadUint16(pubData, offset) tx = &txtypes.DepositNftTxInfo{ TxType: txType, - IsNewNft: isNewNft, AccountIndex: int64(accountIndex), NftIndex: nftIndex, NftL1Address: nftL1Address, diff --git a/common/prove/deposit_nft.go b/common/prove/deposit_nft.go index 9af62669e..7451480cb 100644 --- a/common/prove/deposit_nft.go +++ b/common/prove/deposit_nft.go @@ -40,7 +40,6 @@ func (w *WitnessHelper) constructDepositNftTxWitness(cryptoTx *TxWitness, oTx *t func toCryptoDepositNftTx(txInfo *txtypes.DepositNftTxInfo) (info *cryptoTypes.DepositNftTx, err error) { info = &cryptoTypes.DepositNftTx{ - IsNewNft: txInfo.IsNewNft, AccountIndex: txInfo.AccountIndex, NftIndex: txInfo.NftIndex, NftL1Address: txInfo.NftL1Address, diff --git a/core/executor/deposit_nft_executor.go b/core/executor/deposit_nft_executor.go index 2c6642235..b0c119b2a 100644 --- a/core/executor/deposit_nft_executor.go +++ b/core/executor/deposit_nft_executor.go @@ -20,8 +20,6 @@ type DepositNftExecutor struct { BaseExecutor txInfo *txtypes.DepositNftTxInfo - - isNewNft bool } func NewDepositNftExecutor(bc IBlockchain, tx *tx.Tx) (TxExecutor, error) { @@ -66,17 +64,10 @@ func (e *DepositNftExecutor) Prepare() error { // Set the right account index. txInfo.AccountIndex = account.AccountIndex - // Check if it is a new nft, or it is a nft previously withdraw from layer2. - if txInfo.IsNewNft == 1 { - e.isNewNft = true - // Set new nft index for new nft. - txInfo.NftIndex = bc.StateDB().GetNextNftIndex() - } else { - _, err = e.bc.StateDB().PrepareNft(txInfo.NftIndex) - if err != nil { - logx.Errorf("prepare nft failed") - return err - } + _, err = e.bc.StateDB().PrepareNft(txInfo.NftIndex) + if err != nil { + logx.Errorf("prepare nft failed") + return err } // Mark the tree states that would be affected in this executor. @@ -90,9 +81,6 @@ func (e *DepositNftExecutor) VerifyInputs(skipGasAmtChk bool) error { txInfo := e.txInfo nft, err := bc.StateDB().GetNft(txInfo.NftIndex) - if e.isNewNft && nft == nil { - return nil - } if err != nil { return err } @@ -118,11 +106,7 @@ func (e *DepositNftExecutor) ApplyTransaction() error { } stateCache := e.bc.StateDB() - if e.isNewNft { - stateCache.SetPendingNewNft(txInfo.NftIndex, nft) - } else { - stateCache.SetPendingUpdateNft(txInfo.NftIndex, nft) - } + stateCache.SetPendingUpdateNft(txInfo.NftIndex, nft) return e.BaseExecutor.ApplyTransaction() } @@ -131,7 +115,6 @@ func (e *DepositNftExecutor) GeneratePubData() error { var buf bytes.Buffer buf.WriteByte(uint8(types.TxTypeDepositNft)) - buf.WriteByte(txInfo.IsNewNft) buf.Write(common2.Uint32ToBytes(uint32(txInfo.AccountIndex))) buf.Write(common2.Uint40ToBytes(txInfo.NftIndex)) buf.Write(common2.AddressStrToBytes(txInfo.NftL1Address)) diff --git a/go.mod b/go.mod index e8062f5a1..6101dbd2d 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/dgraph-io/ristretto v0.1.0 github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/panjf2000/ants/v2 v2.5.0 + github.com/prometheus/client_golang v1.12.2 github.com/zeromicro/go-zero v1.3.4 gorm.io/gorm v1.23.4 ) @@ -55,7 +56,6 @@ require ( github.com/pegasus-kv/thrift v0.13.0 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.33.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect @@ -90,7 +90,7 @@ require ( ) require ( - github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220929142710-f30d7d0a9428 + github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220930094817-c69f57d0225b github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f github.com/consensys/gnark v0.7.0 diff --git a/go.sum b/go.sum index d421d9adb..81fd17466 100644 --- a/go.sum +++ b/go.sum @@ -117,10 +117,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220928090246-9a20106a2347 h1:Dv+ztM5Bb8I2m3cf5WDYZZ+sFmNhWzNS41cxAx2AUrc= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220928090246-9a20106a2347/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220929142710-f30d7d0a9428 h1:tC1qPYsjy9KY0LoRuvnXyQI0RdyYWd5E5QyOGP5d35M= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220929142710-f30d7d0a9428/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220930094817-c69f57d0225b h1:LZds9MhqLIQde7VMN/Z8gocVZ+BOknV0TCy2TIqUnKE= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220930094817-c69f57d0225b/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 h1:1rMa8XpplDNZaxeM1ifXMjSSeH/ucJyLUjHHEw1z4AA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2/go.mod h1:T69T8enicQ5kSRPIzyPJv/jhuvRMz1UxsijPXmlis+I= github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f h1:zBVWOWlH4w18O6wp0gZML4U2n1rxsFLb7KB7DFE8zcQ= diff --git a/types/tx.go b/types/tx.go index f4134490d..cd5291dae 100644 --- a/types/tx.go +++ b/types/tx.go @@ -68,7 +68,6 @@ func IsPriorityOperationTx(txType int64) bool { const ( TxTypeBytesSize = 1 - IsNewNftSize = 1 AddressBytesSize = 20 AccountIndexBytesSize = 4 AccountNameBytesSize = 32 @@ -86,7 +85,7 @@ const ( AccountNameHashBytesSize + PubkeyBytesSize + PubkeyBytesSize DepositPubDataSize = TxTypeBytesSize + AccountIndexBytesSize + AccountNameHashBytesSize + AssetIdBytesSize + StateAmountBytesSize - DepositNftPubDataSize = TxTypeBytesSize + IsNewNftSize + AccountIndexBytesSize + NftIndexBytesSize + AddressBytesSize + + DepositNftPubDataSize = TxTypeBytesSize + AccountIndexBytesSize + NftIndexBytesSize + AddressBytesSize + AccountIndexBytesSize + FeeRateBytesSize + NftContentHashBytesSize + NftTokenIdBytesSize + AccountNameHashBytesSize + CollectionIdBytesSize FullExitPubDataSize = TxTypeBytesSize + AccountIndexBytesSize + From 18c0aad5cbd9b7c6f28802edf54cbe5189d9521b Mon Sep 17 00:00:00 2001 From: lightning-li Date: Mon, 10 Oct 2022 20:05:38 +0800 Subject: [PATCH 15/23] fix bug when there are mintNft/registerAccount and other txs which use the new nft and account (#217) --- core/executor/deposit_executor.go | 7 +++++++ core/executor/deposit_nft_executor.go | 7 +++++++ core/executor/full_exit_executor.go | 7 +++++++ core/executor/full_exit_nft_executor.go | 7 +++++++ core/statedb/state_cache.go | 10 ++++++++++ dao/account/account.go | 6 +++++- dao/nft/nft.go | 5 ++++- 7 files changed, 47 insertions(+), 2 deletions(-) diff --git a/core/executor/deposit_executor.go b/core/executor/deposit_executor.go index 1ed405f75..72aac9aec 100644 --- a/core/executor/deposit_executor.go +++ b/core/executor/deposit_executor.go @@ -44,7 +44,14 @@ func (e *DepositExecutor) Prepare() error { account, err := bc.DB().AccountModel.GetAccountByNameHash(accountNameHash) if err != nil { exist := false + var newAccountIndexes []int64 for index := range bc.StateDB().PendingNewAccountMap { + newAccountIndexes = append(newAccountIndexes, index) + } + for index := range bc.StateDB().PendingUpdateAccountMap { + newAccountIndexes = append(newAccountIndexes, index) + } + for _, index := range newAccountIndexes { tempAccount, err := bc.StateDB().GetAccount(index) if err != nil { continue diff --git a/core/executor/deposit_nft_executor.go b/core/executor/deposit_nft_executor.go index b0c119b2a..be818d13c 100644 --- a/core/executor/deposit_nft_executor.go +++ b/core/executor/deposit_nft_executor.go @@ -44,7 +44,14 @@ func (e *DepositNftExecutor) Prepare() error { account, err := bc.DB().AccountModel.GetAccountByNameHash(accountNameHash) if err != nil { exist := false + var newAccountIndexes []int64 for index := range bc.StateDB().PendingNewAccountMap { + newAccountIndexes = append(newAccountIndexes, index) + } + for index := range bc.StateDB().PendingUpdateAccountMap { + newAccountIndexes = append(newAccountIndexes, index) + } + for _, index := range newAccountIndexes { tempAccount, err := bc.StateDB().GetAccount(index) if err != nil { continue diff --git a/core/executor/full_exit_executor.go b/core/executor/full_exit_executor.go index 2d896b7d3..fed7a0f76 100644 --- a/core/executor/full_exit_executor.go +++ b/core/executor/full_exit_executor.go @@ -44,7 +44,14 @@ func (e *FullExitExecutor) Prepare() error { account, err := bc.DB().AccountModel.GetAccountByNameHash(accountNameHash) if err != nil { exist := false + var newAccountIndexes []int64 for index := range bc.StateDB().PendingNewAccountMap { + newAccountIndexes = append(newAccountIndexes, index) + } + for index := range bc.StateDB().PendingUpdateAccountMap { + newAccountIndexes = append(newAccountIndexes, index) + } + for _, index := range newAccountIndexes { tempAccount, err := bc.StateDB().GetAccount(index) if err != nil { continue diff --git a/core/executor/full_exit_nft_executor.go b/core/executor/full_exit_nft_executor.go index ff306c424..a4a2f0a26 100644 --- a/core/executor/full_exit_nft_executor.go +++ b/core/executor/full_exit_nft_executor.go @@ -46,7 +46,14 @@ func (e *FullExitNftExecutor) Prepare() error { account, err := bc.DB().AccountModel.GetAccountByNameHash(accountNameHash) if err != nil { exist := false + var newAccountIndexes []int64 for index := range bc.StateDB().PendingNewAccountMap { + newAccountIndexes = append(newAccountIndexes, index) + } + for index := range bc.StateDB().PendingUpdateAccountMap { + newAccountIndexes = append(newAccountIndexes, index) + } + for _, index := range newAccountIndexes { tempAccount, err := bc.StateDB().GetAccount(index) if err != nil { continue diff --git a/core/statedb/state_cache.go b/core/statedb/state_cache.go index 9950e2e7b..2ceea65bf 100644 --- a/core/statedb/state_cache.go +++ b/core/statedb/state_cache.go @@ -107,6 +107,11 @@ func (c *StateCache) SetPendingNewAccount(accountIndex int64, account *types.Acc } func (c *StateCache) SetPendingUpdateAccount(accountIndex int64, account *types.AccountInfo) { + // TO confirm: why need a separate PendingNewAccount Map + _, exist := c.PendingNewAccountMap[accountIndex] + if exist { + delete(c.PendingNewAccountMap, accountIndex) + } c.PendingUpdateAccountMap[accountIndex] = account } @@ -115,5 +120,10 @@ func (c *StateCache) SetPendingNewNft(nftIndex int64, nft *nft.L2Nft) { } func (c *StateCache) SetPendingUpdateNft(nftIndex int64, nft *nft.L2Nft) { + // TO confirm: why need a separate PendingNewAccount Map + _, exist := c.PendingNewNftMap[nftIndex] + if exist { + delete(c.PendingNewNftMap, nftIndex) + } c.PendingUpdateNftMap[nftIndex] = nft } diff --git a/dao/account/account.go b/dao/account/account.go index 3342266ab..d9f5c4a76 100644 --- a/dao/account/account.go +++ b/dao/account/account.go @@ -181,7 +181,11 @@ func (m *defaultAccountModel) UpdateAccountsInTransact(tx *gorm.DB, accounts []* return dbTx.Error } if dbTx.RowsAffected == 0 { - return types.DbErrFailToUpdateAccount + // this account is new, we need create first + dbTx = tx.Table(m.table).Create(&account) + if dbTx.Error != nil { + return dbTx.Error + } } } return nil diff --git a/dao/nft/nft.go b/dao/nft/nft.go index e127ac9d4..dd95ba9c4 100644 --- a/dao/nft/nft.go +++ b/dao/nft/nft.go @@ -138,7 +138,10 @@ func (m *defaultL2NftModel) UpdateNftsInTransact(tx *gorm.DB, nfts []*L2Nft) err return dbTx.Error } if dbTx.RowsAffected == 0 { - return types.DbErrFailToUpdateNft + dbTx = tx.Table(m.table).Create(&pendingNft) + if dbTx.Error != nil { + return dbTx.Error + } } } return nil From a636b566902e0ff63cd7928b6918c10c653a9d2b Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Tue, 11 Oct 2022 16:00:53 +0800 Subject: [PATCH 16/23] feat: add totalAssetValue in GetAccount API response (#214) Co-authored-by: carlcarl --- docs/api_reference.md | 17 +++++----- .../internal/logic/account/getaccountlogic.go | 31 ++++++++++++++++--- service/apiserver/server.api | 13 ++++---- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/docs/api_reference.md b/docs/api_reference.md index 5c22e2419..b89ce7a2b 100644 --- a/docs/api_reference.md +++ b/docs/api_reference.md @@ -449,14 +449,15 @@ Send raw transaction #### Account -| Name | Type | Description | Required | -|--------|-----------------------------------| ----------- | -------- | -| status | integer | | Yes | -| index | long | | Yes | -| name | string | | Yes | -| pk | string | | Yes | -| nonce | long | | Yes | -| assets | [ [AccountAsset](#accountasset) ] | | Yes | +| Name | Type | Description | Required | +|--------------------|-----------------------------------| ----------- | -------- | +| status | integer | | Yes | +| index | long | | Yes | +| name | string | | Yes | +| pk | string | | Yes | +| nonce | long | | Yes | +| assets | [ [AccountAsset](#accountasset) ] | | Yes | +| total_asset_value | string | | Yes | #### AccountAsset diff --git a/service/apiserver/internal/logic/account/getaccountlogic.go b/service/apiserver/internal/logic/account/getaccountlogic.go index 0b2e0e89a..f953042d5 100644 --- a/service/apiserver/internal/logic/account/getaccountlogic.go +++ b/service/apiserver/internal/logic/account/getaccountlogic.go @@ -2,6 +2,7 @@ package account import ( "context" + "math/big" "sort" "strconv" @@ -76,6 +77,9 @@ func (l *GetAccountLogic) GetAccount(req *types.ReqGetAccount) (resp *types.Acco Nonce: account.Nonce, Assets: make([]*types.AccountAsset, 0, len(account.AssetInfo)), } + + totalAssetValue := big.NewFloat(0) + for _, asset := range account.AssetInfo { if asset.AssetId > maxAssetId { continue //it is used for offer related, or empty balance; max ip id should be less than max asset id @@ -86,14 +90,17 @@ func (l *GetAccountLogic) GetAccount(req *types.ReqGetAccount) (resp *types.Acco if asset.Balance != nil && asset.Balance.Cmp(types2.ZeroBigInt) > 0 { var assetName, assetSymbol string var assetPrice float64 - assetName, err = l.svcCtx.MemCache.GetAssetNameById(asset.AssetId) - if err != nil { - return nil, types2.AppErrInternal - } - assetSymbol, err = l.svcCtx.MemCache.GetAssetSymbolById(asset.AssetId) + + assetInfo, err := l.svcCtx.MemCache.GetAssetByIdWithFallback(asset.AssetId, func() (interface{}, error) { + + return l.svcCtx.AssetModel.GetAssetById(asset.AssetId) + }) if err != nil { return nil, types2.AppErrInternal } + assetName = assetInfo.AssetName + assetSymbol = assetInfo.AssetSymbol + assetPrice, err = l.svcCtx.PriceFetcher.GetCurrencyPrice(l.ctx, assetSymbol) if err != nil { return nil, types2.AppErrInternal @@ -104,9 +111,23 @@ func (l *GetAccountLogic) GetAccount(req *types.ReqGetAccount) (resp *types.Acco Balance: asset.Balance.String(), Price: strconv.FormatFloat(assetPrice, 'E', -1, 64), }) + + // BNB for example: + // 1. Convert unit of balance from wei to BNB + // 2. Calculate the result of (BNB balance * price per BNB) + balanceInFloat := new(big.Float).SetInt(asset.Balance) + unitConversion := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(assetInfo.Decimals)), nil) + assetValue := balanceInFloat.Mul( + new(big.Float).Quo(balanceInFloat, new(big.Float).SetInt(unitConversion)), + big.NewFloat(assetPrice), + ) + + totalAssetValue = totalAssetValue.Add(totalAssetValue, assetValue) } } + resp.TotalAssetValue = totalAssetValue.Text('f', -1) + sort.Slice(resp.Assets, func(i, j int) bool { return resp.Assets[i].Id < resp.Assets[j].Id }) diff --git a/service/apiserver/server.api b/service/apiserver/server.api index b854e7e00..f387d8bde 100644 --- a/service/apiserver/server.api +++ b/service/apiserver/server.api @@ -41,12 +41,13 @@ type ( } Account { - Status uint32 `json:"status"` - Index int64 `json:"index"` - Name string `json:"name"` - Pk string `json:"pk"` - Nonce int64 `json:"nonce"` - Assets []*AccountAsset `json:"assets"` + Status uint32 `json:"status"` + Index int64 `json:"index"` + Name string `json:"name"` + Pk string `json:"pk"` + Nonce int64 `json:"nonce"` + Assets []*AccountAsset `json:"assets"` + TotalAssetValue string `json:"total_asset_value"` } SimpleAccount { From 5050fa518d8a7271b108bbc1a91761cfb22b1d33 Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Wed, 12 Oct 2022 10:02:49 +0800 Subject: [PATCH 17/23] executor: fix full exit nft (#220) Co-authored-by: Keefe Liu --- core/executor/full_exit_nft_executor.go | 48 +++++-------------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/core/executor/full_exit_nft_executor.go b/core/executor/full_exit_nft_executor.go index a4a2f0a26..7cf5eefe1 100644 --- a/core/executor/full_exit_nft_executor.go +++ b/core/executor/full_exit_nft_executor.go @@ -21,7 +21,8 @@ type FullExitNftExecutor struct { txInfo *txtypes.FullExitNftTxInfo - exitNft *nft.L2Nft + exitNft *nft.L2Nft + exitEmpty bool } func NewFullExitNftExecutor(bc IBlockchain, tx *tx.Tx) (TxExecutor, error) { @@ -90,11 +91,11 @@ func (e *FullExitNftExecutor) Prepare() error { var isExitEmptyNft = true nft, err := e.bc.StateDB().PrepareNft(txInfo.NftIndex) - if err != nil { + if err != nil && err != types.DbErrNotFound { return err } - if nft.OwnerAccountIndex == account.AccountIndex { + if err == nil && nft.OwnerAccountIndex == account.AccountIndex { // Set the right nft if the owner is correct. exitNft = nft isExitEmptyNft = false @@ -102,9 +103,6 @@ func (e *FullExitNftExecutor) Prepare() error { // Mark the tree states that would be affected in this executor. e.MarkNftDirty(txInfo.NftIndex) - if exitNft.CreatorAccountIndex != types.NilAccountIndex { - e.MarkAccountAssetsDirty(exitNft.CreatorAccountIndex, []int64{}) - } e.MarkAccountAssetsDirty(txInfo.AccountIndex, []int64{0}) // Prepare asset 0 for generate an empty tx detail. err = e.BaseExecutor.Prepare() if err != nil { @@ -115,7 +113,7 @@ func (e *FullExitNftExecutor) Prepare() error { txInfo.CreatorAccountIndex = exitNft.CreatorAccountIndex txInfo.CreatorTreasuryRate = exitNft.CreatorTreasuryRate txInfo.CreatorAccountNameHash = common.FromHex(types.EmptyAccountNameHash) - if isExitEmptyNft { + if !isExitEmptyNft { creator, err := bc.StateDB().GetFormatAccount(exitNft.CreatorAccountIndex) if err != nil { return err @@ -128,45 +126,21 @@ func (e *FullExitNftExecutor) Prepare() error { txInfo.CollectionId = exitNft.CollectionId e.exitNft = exitNft + e.exitEmpty = isExitEmptyNft return nil } func (e *FullExitNftExecutor) VerifyInputs(skipGasAmtChk bool) error { - bc := e.bc - txInfo := e.txInfo - - nft, err := bc.StateDB().GetNft(txInfo.NftIndex) - if err != nil { - return err - } - if txInfo.AccountIndex != nft.OwnerAccountIndex { - // The check is not fully enough, just avoid explicit error. - if !bytes.Equal(txInfo.NftContentHash, common.FromHex(types.EmptyNftContentHash)) { - return errors.New("invalid nft content hash") - } - } else { - // The check is not fully enough, just avoid explicit error. - if !bytes.Equal(txInfo.NftContentHash, common.FromHex(nft.NftContentHash)) { - return errors.New("invalid nft content hash") - } - } - return nil } func (e *FullExitNftExecutor) ApplyTransaction() error { - bc := e.bc - txInfo := e.txInfo - oldNft, err := bc.StateDB().GetNft(txInfo.NftIndex) - if err != nil { - return err - } - if txInfo.AccountIndex != oldNft.OwnerAccountIndex { - // Do nothing. + if e.exitEmpty { return nil } // Set nft to empty nft. + txInfo := e.txInfo emptyNftInfo := types.EmptyNftInfo(txInfo.NftIndex) emptyNft := &nft.L2Nft{ NftIndex: emptyNftInfo.NftIndex, @@ -261,14 +235,10 @@ func (e *FullExitNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { }) // nft info order++ - oldNft, err := bc.StateDB().GetNft(txInfo.NftIndex) - if err != nil { - return nil, err - } emptyNft := types.EmptyNftInfo(txInfo.NftIndex) baseNft := emptyNft newNft := emptyNft - + oldNft, _ := bc.StateDB().GetNft(txInfo.NftIndex) if oldNft != nil { baseNft = types.ConstructNftInfo( oldNft.NftIndex, From af706f4850502305940646d5a67279b12f75450c Mon Sep 17 00:00:00 2001 From: WayToFuture Date: Wed, 12 Oct 2022 10:58:58 +0800 Subject: [PATCH 18/23] core: move gas to block level (#206) --- .gitignore | 4 +- common/prove/types.go | 3 +- common/prove/witness_helper.go | 226 +++++++++++++++++++- common/prove/witness_test.go | 18 +- core/executor/atomic_match_executor.go | 22 +- core/executor/cancel_offer_executor.go | 8 +- core/executor/create_collection_executor.go | 8 +- core/executor/mint_nft_executor.go | 8 +- core/executor/transfer_executor.go | 11 +- core/executor/transfer_nft_executor.go | 12 +- core/executor/withdraw_executor.go | 8 +- core/executor/withdraw_nft_executor.go | 8 +- core/statedb/state_cache.go | 19 ++ core/statedb/statedb.go | 96 ++++++++- dao/account/account_history.go | 13 +- dao/tx/tx_detail.go | 1 + deploy-qa.sh | 1 + go.mod | 4 +- go.sum | 7 +- service/committer/committer/committer.go | 10 +- service/monitor/monitor/monitor.go | 4 +- service/prover/prover/prover.go | 4 + service/witness/witness/witness.go | 14 +- tree/asset_tree_cache.go | 3 +- types/account.go | 4 +- types/constant.go | 2 + 26 files changed, 431 insertions(+), 87 deletions(-) diff --git a/.gitignore b/.gitignore index af1d9745d..b25dbe2a5 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,6 @@ vendor deployment/dependency deployment/configs deployment/.zkbnb -run_*.sh \ No newline at end of file +run_*.sh + +own* \ No newline at end of file diff --git a/common/prove/types.go b/common/prove/types.go index 5a6ed89d0..7120df119 100644 --- a/common/prove/types.go +++ b/common/prove/types.go @@ -26,7 +26,8 @@ import ( ) type ( - TxWitness = circuit.Tx + TxWitness = circuit.Tx + GasWitness = circuit.Gas ) const ( diff --git a/common/prove/witness_helper.go b/common/prove/witness_helper.go index d4ae44b20..efe6b4703 100644 --- a/common/prove/witness_helper.go +++ b/common/prove/witness_helper.go @@ -22,12 +22,16 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/zeromicro/go-zero/core/logx" + "github.com/bnb-chain/zkbnb-crypto/circuit" cryptoTypes "github.com/bnb-chain/zkbnb-crypto/circuit/types" + "github.com/bnb-chain/zkbnb-crypto/ffmath" bsmt "github.com/bnb-chain/zkbnb-smt" common2 "github.com/bnb-chain/zkbnb/common" "github.com/bnb-chain/zkbnb/common/chain" "github.com/bnb-chain/zkbnb/dao/account" + "github.com/bnb-chain/zkbnb/dao/block" "github.com/bnb-chain/zkbnb/dao/tx" "github.com/bnb-chain/zkbnb/tree" "github.com/bnb-chain/zkbnb/types" @@ -36,7 +40,10 @@ import ( type WitnessHelper struct { treeCtx *tree.Context - accountModel account.AccountModel + accountModel account.AccountModel + accountHistoryModel account.AccountHistoryModel + + gasAccountInfo *types.AccountInfo //gas account cache // Trees accountTree bsmt.SparseMerkleTree @@ -45,13 +52,14 @@ type WitnessHelper struct { } func NewWitnessHelper(treeCtx *tree.Context, accountTree, nftTree bsmt.SparseMerkleTree, - assetTrees *tree.AssetTreeCache, accountModel account.AccountModel) *WitnessHelper { + assetTrees *tree.AssetTreeCache, accountModel account.AccountModel, accountHistoryModel account.AccountHistoryModel) *WitnessHelper { return &WitnessHelper{ - treeCtx: treeCtx, - accountModel: accountModel, - accountTree: accountTree, - assetTrees: assetTrees, - nftTree: nftTree, + treeCtx: treeCtx, + accountModel: accountModel, + accountHistoryModel: accountHistoryModel, + accountTree: accountTree, + assetTrees: assetTrees, + nftTree: nftTree, } } @@ -157,7 +165,7 @@ func (w *WitnessHelper) constructAccountWitness( proverAccounts []*AccountWitnessInfo, ) ( accountRootBefore []byte, - // account before info, size is 5 + // account before info, size is 4 accountsInfoBefore [NbAccountsPerTx]*cryptoTypes.Account, // before account asset merkle proof merkleProofsAccountAssetsBefore [NbAccountsPerTx][NbAccountAssetsPerAccount][AssetMerkleLevels][]byte, @@ -207,6 +215,20 @@ func (w *WitnessHelper) constructAccountWitness( Status: accountInfo.Status, }, }) + + // cache gas account + if accountKey == types.GasAccount { + w.gasAccountInfo = &types.AccountInfo{ + AccountIndex: accountInfo.AccountIndex, + AccountName: accountInfo.AccountName, + PublicKey: accountInfo.PublicKey, + AccountNameHash: accountInfo.AccountNameHash, + Nonce: types.EmptyNonce, + CollectionNonce: types.EmptyCollectionNonce, + AssetRoot: common.Bytes2Hex(tree.NilAccountAssetRoot), + AssetInfo: make(map[int64]*types.AccountAsset, 0), + } + } } else { proverAccountInfo := proverAccounts[accountCount] pk, err := common2.ParsePubKey(proverAccountInfo.AccountInfo.PublicKey) @@ -307,6 +329,21 @@ func (w *WitnessHelper) constructAccountWitness( if err != nil { return accountRootBefore, accountsInfoBefore, merkleProofsAccountAssetsBefore, merkleProofsAccountBefore, err } + + // cache gas account + if accountKey == types.GasAccount { + w.gasAccountInfo.Nonce = nonce + w.gasAccountInfo.CollectionNonce = collectionNonce + w.gasAccountInfo.AssetRoot = common.Bytes2Hex(w.assetTrees.Get(accountKey).Root()) + for i := 0; i < NbAccountAssetsPerAccount; i++ { + w.gasAccountInfo.AssetInfo[cryptoAccount.AssetsInfo[i].AssetId] = &types.AccountAsset{ + AssetId: cryptoAccount.AssetsInfo[i].AssetId, + Balance: cryptoAccount.AssetsInfo[i].Balance, + OfferCanceledOrFinalized: cryptoAccount.AssetsInfo[i].OfferCanceledOrFinalized, + } + } + } + // set account info before accountsInfoBefore[accountCount] = cryptoAccount // add count @@ -472,6 +509,10 @@ func (w *WitnessHelper) constructSimpleWitnessInfo(oTx *tx.Tx) ( accountKeys = append(accountKeys, oTx.AccountIndex) } for _, txDetail := range oTx.TxDetails { + // if tx detail is from gas account + if txDetail.IsGas { + continue + } switch txDetail.AssetType { case types.FungibleAssetType: // get account info @@ -597,3 +638,172 @@ func (w *WitnessHelper) constructSimpleWitnessInfo(oTx *tx.Tx) ( } return accountKeys, accountWitnessInfo, nftWitnessInfo, nil } + +func (w *WitnessHelper) ConstructGasWitness(block *block.Block) (cryptoGas *GasWitness, err error) { + var gas *circuit.Gas + + needGas := false + gasChanges := make(map[int64]*big.Int) + for _, assetId := range types.GasAssets { + gasChanges[assetId] = types.ZeroBigInt + } + for _, tx := range block.Txs { + if types.IsL2Tx(tx.TxType) { + needGas = true + for _, txDetail := range tx.TxDetails { + if txDetail.IsGas { + assetDelta, err := types.ParseAccountAsset(txDetail.BalanceDelta) + if err != nil { + return nil, err + } + gasChanges[assetDelta.AssetId] = ffmath.Add(gasChanges[assetDelta.AssetId], assetDelta.Balance) + } + } + } + } + + gasAccountIndex := types.GasAccount + emptyAssetTree, err := tree.NewMemAccountAssetTree() + if err != nil { + return nil, err + } + if !needGas { // no need of gas for this block + accountInfoBefore := cryptoTypes.EmptyGasAccount(gasAccountIndex, tree.NilAccountAssetRoot) + accountMerkleProofs, err := w.accountTree.GetProof(uint64(gasAccountIndex)) + if err != nil { + return nil, err + } + merkleProofsAccountBefore, err := SetFixedAccountArray(accountMerkleProofs) + if err != nil { + return nil, err + } + merkleProofsAccountAssetsBefore := make([][AssetMerkleLevels][]byte, 0) + for _, assetId := range types.GasAssets { + accountInfoBefore.AssetsInfo = append(accountInfoBefore.AssetsInfo, cryptoTypes.EmptyAccountAsset(assetId)) + assetMerkleProof, err := emptyAssetTree.GetProof(uint64(assetId)) + if err != nil { + return nil, err + } + merkleProofsAccountAssetBefore, err := SetFixedAccountAssetArray(assetMerkleProof) + if err != nil { + return nil, err + } + merkleProofsAccountAssetsBefore = append(merkleProofsAccountAssetsBefore, merkleProofsAccountAssetBefore) + } + gas = &circuit.Gas{ + GasAssetCount: len(types.GasAssets), + AccountInfoBefore: accountInfoBefore, + MerkleProofsAccountBefore: merkleProofsAccountBefore, + MerkleProofsAccountAssetsBefore: merkleProofsAccountAssetsBefore, + } + } else { + pk, err := common2.ParsePubKey(w.gasAccountInfo.PublicKey) + if err != nil { + return nil, err + } + accountInfoBefore := &cryptoTypes.GasAccount{ + AccountIndex: gasAccountIndex, + AccountNameHash: common.FromHex(w.gasAccountInfo.AccountNameHash), + AccountPk: pk, + Nonce: w.gasAccountInfo.Nonce, + CollectionNonce: w.gasAccountInfo.CollectionNonce, + AssetRoot: w.assetTrees.Get(gasAccountIndex).Root(), + } + logx.Infof("old gas account asset root: %s", common.Bytes2Hex(w.assetTrees.Get(gasAccountIndex).Root())) + + accountMerkleProofs, err := w.accountTree.GetProof(uint64(gasAccountIndex)) + if err != nil { + return nil, err + } + merkleProofsAccountBefore, err := SetFixedAccountArray(accountMerkleProofs) + if err != nil { + return nil, err + } + merkleProofsAccountAssetsBefore := make([][AssetMerkleLevels][]byte, 0) + for _, assetId := range types.GasAssets { + assetMerkleProof, err := w.assetTrees.Get(gasAccountIndex).GetProof(uint64(assetId)) + if err != nil { + return nil, err + } + balanceBefore := types.ZeroBigInt + offerCanceledOrFinalized := types.ZeroBigInt + if asset, ok := w.gasAccountInfo.AssetInfo[assetId]; ok { + balanceBefore = asset.Balance + offerCanceledOrFinalized = asset.OfferCanceledOrFinalized + } + accountInfoBefore.AssetsInfo = append(accountInfoBefore.AssetsInfo, &cryptoTypes.AccountAsset{ + AssetId: assetId, + Balance: balanceBefore, + OfferCanceledOrFinalized: offerCanceledOrFinalized, + }) + + // set merkle proof + merkleProofsAccountAssetBefore, err := SetFixedAccountAssetArray(assetMerkleProof) + if err != nil { + return nil, err + } + merkleProofsAccountAssetsBefore = append(merkleProofsAccountAssetsBefore, merkleProofsAccountAssetBefore) + + balanceAfter := ffmath.Add(balanceBefore, gasChanges[assetId]) + nAssetHash, err := tree.ComputeAccountAssetLeafHash(balanceAfter.String(), offerCanceledOrFinalized.String()) + if err != nil { + return nil, err + } + err = w.assetTrees.Get(gasAccountIndex).Set(uint64(assetId), nAssetHash) + if err != nil { + return nil, err + } + + } + logx.Infof("new gas account asset root: %s", common.Bytes2Hex(w.assetTrees.Get(gasAccountIndex).Root())) + + nAccountHash, err := tree.ComputeAccountLeafHash( + w.gasAccountInfo.AccountNameHash, + w.gasAccountInfo.PublicKey, + w.gasAccountInfo.Nonce, + w.gasAccountInfo.CollectionNonce, + w.assetTrees.Get(gasAccountIndex).Root(), + ) + if err != nil { + return nil, err + } + err = w.accountTree.Set(uint64(gasAccountIndex), nAccountHash) + if err != nil { + return nil, err + } + gas = &circuit.Gas{ + GasAssetCount: len(types.GasAssets), + AccountInfoBefore: accountInfoBefore, + MerkleProofsAccountBefore: merkleProofsAccountBefore, + MerkleProofsAccountAssetsBefore: merkleProofsAccountAssetsBefore, + } + } + + return gas, nil +} + +func (w *WitnessHelper) ResetCache(height int64) error { + w.gasAccountInfo = nil + history, err := w.accountHistoryModel.GetLatestAccountHistory(types.GasAccount, height) + if err != nil && err != types.DbErrNotFound { + return err + } + + if history != nil { + gasAccount, err := w.accountModel.GetConfirmedAccountByIndex(types.GasAccount) + if err != nil && err != types.DbErrNotFound { + return err + } + gasAccount.Nonce = history.Nonce + gasAccount.CollectionNonce = history.CollectionNonce + gasAccount.AssetInfo = history.AssetInfo + gasAccount.AssetRoot = history.AssetRoot + formatGasAccount, err := chain.ToFormatAccountInfo(gasAccount) + if err != nil { + return err + } + + w.gasAccountInfo = formatGasAccount + } + return nil +} diff --git a/common/prove/witness_test.go b/common/prove/witness_test.go index 02ba66463..84b9d1e89 100644 --- a/common/prove/witness_test.go +++ b/common/prove/witness_test.go @@ -47,10 +47,10 @@ var ( assetTreeCacheSize = 512000 ) -func TestConstructTxWitness(t *testing.T) { +func TestConstructWitness(t *testing.T) { testDBSetup() defer testDBShutdown() - maxTestBlockHeight := int64(33) + maxTestBlockHeight := int64(49) for h := int64(1); h < maxTestBlockHeight; h++ { witnessHelper, err := getWitnessHelper(h - 1) assert.NoError(t, err) @@ -61,6 +61,8 @@ func TestConstructTxWitness(t *testing.T) { var cBlock circuit.Block err = json.Unmarshal([]byte(w.WitnessData), &cBlock) assert.NoError(t, err) + err = witnessHelper.ResetCache(h) + assert.NoError(t, err) for idx, tx := range b[0].Txs { txWitness, err := witnessHelper.ConstructTxWitness(tx, uint64(0)) assert.NoError(t, err) @@ -68,6 +70,11 @@ func TestConstructTxWitness(t *testing.T) { actualBz, _ := json.Marshal(txWitness) assert.Equal(t, string(actualBz), string(expectedBz), fmt.Sprintf("block %d, tx %d generate witness failed, tx type: %d", h, idx, tx.TxType)) } + gasWitness, err := witnessHelper.ConstructGasWitness(b[0]) + assert.NoError(t, err) + expectedBz, _ := json.Marshal(cBlock.Gas) + actualBz, _ := json.Marshal(gasWitness) + assert.Equal(t, string(actualBz), string(expectedBz), fmt.Sprintf("block %d, gas generate witness failed", h)) } } @@ -88,7 +95,8 @@ func getWitnessHelper(blockHeight int64) (*WitnessHelper, error) { accountTree, nftTree, accountAssetTrees, - accountModel), nil + accountModel, + accountHistoryModel), nil } func testDBSetup() { @@ -96,11 +104,11 @@ func testDBSetup() { time.Sleep(5 * time.Second) cmd := exec.Command("docker", "run", "--name", "postgres-ut-witness", "-p", "5434:5432", "-e", "POSTGRES_PASSWORD=ZkBNB@123", "-e", "POSTGRES_USER=postgres", "-e", "POSTGRES_DB=zkbnb", - "-e", "PGDATA=/var/lib/postgresql/pgdata", "-d", "ghcr.io/bnb-chain/zkbnb/zkbnb-ut-postgres:igor") + "-e", "PGDATA=/var/lib/postgresql/pgdata", "-d", "ghcr.io/bnb-chain/zkbnb/zkbnb-ut-postgres:blockgas") if err := cmd.Run(); err != nil { panic(err) } - time.Sleep(5 * time.Second) + time.Sleep(15 * time.Second) db, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{}) blockModel = block.NewBlockModel(db) witnessModel = blockwitness.NewBlockWitnessModel(db) diff --git a/core/executor/atomic_match_executor.go b/core/executor/atomic_match_executor.go index ec27d92d6..52d69932c 100644 --- a/core/executor/atomic_match_executor.go +++ b/core/executor/atomic_match_executor.go @@ -91,6 +91,17 @@ func (e *AtomicMatchExecutor) VerifyInputs(skipGasAmtChk bool) error { return errors.New("buy offer mismatches sell offer") } + // only gas assets are allowed for atomic match + found := false + for _, assetId := range types.GasAssets { + if assetId == txInfo.SellOffer.AssetId { + found = true + } + } + if !found { + return errors.New("invalid asset of offer") + } + // Check offer expired time. if err := e.bc.VerifyExpiredAt(txInfo.BuyOffer.ExpiredAt); err != nil { return errors.New("invalid BuyOffer.ExpiredAt") @@ -173,10 +184,6 @@ func (e *AtomicMatchExecutor) ApplyTransaction() error { if err != nil { return err } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } buyAccount, err := bc.StateDB().GetFormatAccount(txInfo.BuyOffer.AccountIndex) if err != nil { return err @@ -195,8 +202,6 @@ func (e *AtomicMatchExecutor) ApplyTransaction() error { sellAccount.AssetInfo[txInfo.SellOffer.AssetId].Balance = ffmath.Add(sellAccount.AssetInfo[txInfo.SellOffer.AssetId].Balance, ffmath.Sub( txInfo.BuyOffer.AssetAmount, ffmath.Add(txInfo.TreasuryAmount, txInfo.CreatorAmount))) creatorAccount.AssetInfo[txInfo.BuyOffer.AssetId].Balance = ffmath.Add(creatorAccount.AssetInfo[txInfo.BuyOffer.AssetId].Balance, txInfo.CreatorAmount) - gasAccount.AssetInfo[txInfo.BuyOffer.AssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.BuyOffer.AssetId].Balance, txInfo.TreasuryAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) fromAccount.Nonce++ sellOffer := sellAccount.AssetInfo[e.sellOfferAssetId].OfferCanceledOrFinalized @@ -213,9 +218,10 @@ func (e *AtomicMatchExecutor) ApplyTransaction() error { stateCache.SetPendingUpdateAccount(fromAccount.AccountIndex, fromAccount) stateCache.SetPendingUpdateAccount(buyAccount.AccountIndex, buyAccount) stateCache.SetPendingUpdateAccount(sellAccount.AccountIndex, sellAccount) - stateCache.SetPendingUpdateAccount(gasAccount.AccountIndex, gasAccount) stateCache.SetPendingUpdateAccount(creatorAccount.AccountIndex, creatorAccount) stateCache.SetPendingUpdateNft(matchNft.NftIndex, matchNft) + stateCache.SetPendingUpdateGas(txInfo.BuyOffer.AssetId, txInfo.TreasuryAmount) + stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } @@ -457,6 +463,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountOrder: accountOrder, Nonce: gasAccount.Nonce, CollectionNonce: gasAccount.CollectionNonce, + IsGas: true, }) gasAccount.AssetInfo[txInfo.BuyOffer.AssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.BuyOffer.AssetId].Balance, txInfo.TreasuryAmount) @@ -474,6 +481,7 @@ func (e *AtomicMatchExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountOrder: accountOrder, Nonce: gasAccount.Nonce, CollectionNonce: gasAccount.CollectionNonce, + IsGas: true, }) gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) diff --git a/core/executor/cancel_offer_executor.go b/core/executor/cancel_offer_executor.go index 66fd7f7a6..05838f03b 100644 --- a/core/executor/cancel_offer_executor.go +++ b/core/executor/cancel_offer_executor.go @@ -82,13 +82,8 @@ func (e *CancelOfferExecutor) ApplyTransaction() error { if err != nil { return err } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) fromAccount.Nonce++ offerAssetId := txInfo.OfferId / OfferPerAsset @@ -99,7 +94,7 @@ func (e *CancelOfferExecutor) ApplyTransaction() error { stateCache := e.bc.StateDB() stateCache.SetPendingUpdateAccount(fromAccount.AccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(gasAccount.AccountIndex, gasAccount) + stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } @@ -230,6 +225,7 @@ func (e *CancelOfferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { Nonce: gasAccount.Nonce, AccountOrder: accountOrder, CollectionNonce: gasAccount.CollectionNonce, + IsGas: true, }) return txDetails, nil } diff --git a/core/executor/create_collection_executor.go b/core/executor/create_collection_executor.go index 1e9f34e8d..b185ff4ff 100644 --- a/core/executor/create_collection_executor.go +++ b/core/executor/create_collection_executor.go @@ -81,20 +81,15 @@ func (e *CreateCollectionExecutor) ApplyTransaction() error { if err != nil { return err } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } // apply changes fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) fromAccount.Nonce++ fromAccount.CollectionNonce++ stateCache := e.bc.StateDB() stateCache.SetPendingUpdateAccount(fromAccount.AccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(gasAccount.AccountIndex, gasAccount) + stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } @@ -212,6 +207,7 @@ func (e *CreateCollectionExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { Order: order, Nonce: gasAccount.Nonce, AccountOrder: accountOrder, + IsGas: true, }) return txDetails, nil } diff --git a/core/executor/mint_nft_executor.go b/core/executor/mint_nft_executor.go index 1d9694ac6..7324e8bd0 100644 --- a/core/executor/mint_nft_executor.go +++ b/core/executor/mint_nft_executor.go @@ -89,18 +89,12 @@ func (e *MintNftExecutor) ApplyTransaction() error { if err != nil { return err } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } creatorAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(creatorAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) creatorAccount.Nonce++ stateCache := e.bc.StateDB() stateCache.SetPendingUpdateAccount(txInfo.CreatorAccountIndex, creatorAccount) - stateCache.SetPendingUpdateAccount(txInfo.GasAccountIndex, gasAccount) stateCache.SetPendingNewNft(txInfo.NftIndex, &nft.L2Nft{ NftIndex: txInfo.NftIndex, CreatorAccountIndex: txInfo.CreatorAccountIndex, @@ -111,6 +105,7 @@ func (e *MintNftExecutor) ApplyTransaction() error { CreatorTreasuryRate: txInfo.CreatorTreasuryRate, CollectionId: txInfo.NftCollectionId, }) + stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } @@ -264,6 +259,7 @@ func (e *MintNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { Nonce: gasAccount.Nonce, AccountOrder: accountOrder, CollectionNonce: gasAccount.CollectionNonce, + IsGas: true, }) return txDetails, nil } diff --git a/core/executor/transfer_executor.go b/core/executor/transfer_executor.go index 860805403..3956f0559 100644 --- a/core/executor/transfer_executor.go +++ b/core/executor/transfer_executor.go @@ -92,21 +92,16 @@ func (e *TransferExecutor) ApplyTransaction() error { if err != nil { return err } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } fromAccount.AssetInfo[txInfo.AssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.AssetId].Balance, txInfo.AssetAmount) fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) toAccount.AssetInfo[txInfo.AssetId].Balance = ffmath.Add(toAccount.AssetInfo[txInfo.AssetId].Balance, txInfo.AssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) fromAccount.Nonce++ stateCache := e.bc.StateDB() stateCache.SetPendingUpdateAccount(txInfo.FromAccountIndex, fromAccount) stateCache.SetPendingUpdateAccount(txInfo.ToAccountIndex, toAccount) - stateCache.SetPendingUpdateAccount(txInfo.GasAccountIndex, gasAccount) + stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } @@ -189,6 +184,7 @@ func (e *TransferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { CollectionNonce: fromAccount.CollectionNonce, }) fromAccount.AssetInfo[txInfo.AssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.AssetId].Balance, txInfo.AssetAmount) + // from account asset gas order++ txDetails = append(txDetails, &tx.TxDetail{ @@ -205,6 +201,7 @@ func (e *TransferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { CollectionNonce: fromAccount.CollectionNonce, }) fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) + // to account asset a order++ accountOrder++ @@ -222,6 +219,7 @@ func (e *TransferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { CollectionNonce: toAccount.CollectionNonce, }) toAccount.AssetInfo[txInfo.AssetId].Balance = ffmath.Add(toAccount.AssetInfo[txInfo.AssetId].Balance, txInfo.AssetAmount) + // gas account asset gas order++ accountOrder++ @@ -237,6 +235,7 @@ func (e *TransferExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountOrder: accountOrder, Nonce: gasAccount.Nonce, CollectionNonce: gasAccount.CollectionNonce, + IsGas: true, }) gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) diff --git a/core/executor/transfer_nft_executor.go b/core/executor/transfer_nft_executor.go index 8966e8401..7da602fb2 100644 --- a/core/executor/transfer_nft_executor.go +++ b/core/executor/transfer_nft_executor.go @@ -89,28 +89,23 @@ func (e *TransferNftExecutor) ApplyTransaction() error { bc := e.bc txInfo := e.txInfo - fromAccount, err := e.bc.StateDB().GetFormatAccount(txInfo.FromAccountIndex) + fromAccount, err := bc.StateDB().GetFormatAccount(txInfo.FromAccountIndex) if err != nil { return err } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } - nft, err := e.bc.StateDB().GetNft(txInfo.NftIndex) + nft, err := bc.StateDB().GetNft(txInfo.NftIndex) if err != nil { return err } fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) fromAccount.Nonce++ nft.OwnerAccountIndex = txInfo.ToAccountIndex stateCache := e.bc.StateDB() stateCache.SetPendingUpdateAccount(txInfo.FromAccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(txInfo.GasAccountIndex, gasAccount) stateCache.SetPendingUpdateNft(txInfo.NftIndex, nft) + stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } @@ -272,6 +267,7 @@ func (e *TransferNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { Nonce: gasAccount.Nonce, AccountOrder: accountOrder, CollectionNonce: gasAccount.CollectionNonce, + IsGas: true, }) return txDetails, nil } diff --git a/core/executor/withdraw_executor.go b/core/executor/withdraw_executor.go index 7d54cdb43..596fd5fbf 100644 --- a/core/executor/withdraw_executor.go +++ b/core/executor/withdraw_executor.go @@ -79,20 +79,15 @@ func (e *WithdrawExecutor) ApplyTransaction() error { if err != nil { return err } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } // apply changes fromAccount.AssetInfo[txInfo.AssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.AssetId].Balance, txInfo.AssetAmount) fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) fromAccount.Nonce++ stateCache := e.bc.StateDB() stateCache.SetPendingUpdateAccount(txInfo.FromAccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(txInfo.GasAccountIndex, gasAccount) + stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } @@ -215,6 +210,7 @@ func (e *WithdrawExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountOrder: accountOrder, Nonce: gasAccount.Nonce, CollectionNonce: gasAccount.CollectionNonce, + IsGas: true, }) return txDetails, nil } diff --git a/core/executor/withdraw_nft_executor.go b/core/executor/withdraw_nft_executor.go index bebf3cdce..cd5797474 100644 --- a/core/executor/withdraw_nft_executor.go +++ b/core/executor/withdraw_nft_executor.go @@ -115,20 +115,14 @@ func (e *WithdrawNftExecutor) ApplyTransaction() error { if err != nil { return err } - gasAccount, err := bc.StateDB().GetFormatAccount(txInfo.GasAccountIndex) - if err != nil { - return err - } // apply changes fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Sub(fromAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) - gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance = ffmath.Add(gasAccount.AssetInfo[txInfo.GasFeeAssetId].Balance, txInfo.GasFeeAssetAmount) fromAccount.Nonce++ newNftInfo := types.EmptyNftInfo(txInfo.NftIndex) stateCache := e.bc.StateDB() stateCache.SetPendingUpdateAccount(txInfo.AccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(txInfo.GasAccountIndex, gasAccount) stateCache.SetPendingUpdateNft(txInfo.NftIndex, &nft.L2Nft{ Model: oldNft.Model, NftIndex: newNftInfo.NftIndex, @@ -140,6 +134,7 @@ func (e *WithdrawNftExecutor) ApplyTransaction() error { CreatorTreasuryRate: newNftInfo.CreatorTreasuryRate, CollectionId: newNftInfo.CollectionId, }) + stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } @@ -303,6 +298,7 @@ func (e *WithdrawNftExecutor) GenerateTxDetails() ([]*tx.TxDetail, error) { AccountOrder: accountOrder, Nonce: gasAccount.Nonce, CollectionNonce: gasAccount.CollectionNonce, + IsGas: true, }) return txDetails, nil } diff --git a/core/statedb/state_cache.go b/core/statedb/state_cache.go index 2ceea65bf..cf5c61c9f 100644 --- a/core/statedb/state_cache.go +++ b/core/statedb/state_cache.go @@ -1,9 +1,12 @@ package statedb import ( + "math/big" + "github.com/ethereum/go-ethereum/common" cryptoTypes "github.com/bnb-chain/zkbnb-crypto/circuit/types" + "github.com/bnb-chain/zkbnb-crypto/ffmath" "github.com/bnb-chain/zkbnb/dao/nft" "github.com/bnb-chain/zkbnb/dao/tx" "github.com/bnb-chain/zkbnb/types" @@ -24,6 +27,7 @@ type StateCache struct { PendingNewNftMap map[int64]*nft.L2Nft PendingUpdateAccountMap map[int64]*types.AccountInfo PendingUpdateNftMap map[int64]*nft.L2Nft + PendingGasMap map[int64]*big.Int //pending gas changes of a block // Record the tree states that should be updated. dirtyAccountsAndAssetsMap map[int64]map[int64]bool @@ -39,6 +43,7 @@ func NewStateCache(stateRoot string) *StateCache { PendingNewNftMap: make(map[int64]*nft.L2Nft, 0), PendingUpdateAccountMap: make(map[int64]*types.AccountInfo, 0), PendingUpdateNftMap: make(map[int64]*nft.L2Nft, 0), + PendingGasMap: make(map[int64]*big.Int, 0), PubData: make([]byte, 0), PriorityOperations: 0, @@ -127,3 +132,17 @@ func (c *StateCache) SetPendingUpdateNft(nftIndex int64, nft *nft.L2Nft) { } c.PendingUpdateNftMap[nftIndex] = nft } + +func (c *StateCache) GetPendingUpdateGas(assetId int64) *big.Int { + if delta, ok := c.PendingGasMap[assetId]; ok { + return delta + } + return types.ZeroBigInt +} + +func (c *StateCache) SetPendingUpdateGas(assetId int64, balanceDelta *big.Int) { + if _, ok := c.PendingGasMap[assetId]; !ok { + c.PendingGasMap[assetId] = types.ZeroBigInt + } + c.PendingGasMap[assetId] = ffmath.Add(c.PendingGasMap[assetId], balanceDelta) +} diff --git a/core/statedb/statedb.go b/core/statedb/statedb.go index a264352e8..4313bbb6a 100644 --- a/core/statedb/statedb.go +++ b/core/statedb/statedb.go @@ -12,6 +12,7 @@ import ( lru "github.com/hashicorp/golang-lru" "github.com/zeromicro/go-zero/core/logx" + "github.com/bnb-chain/zkbnb-crypto/ffmath" bsmt "github.com/bnb-chain/zkbnb-smt" "github.com/bnb-chain/zkbnb/common/chain" "github.com/bnb-chain/zkbnb/dao/account" @@ -237,6 +238,23 @@ func (s *StateDB) syncPendingNft(pendingNft map[int64]*nft.L2Nft) error { return nil } +func (s *StateDB) SyncPendingGasAccount() error { + if cacheAccount, ok := s.AccountCache.Get(types.GasAccount); ok { + formatAccount := cacheAccount.(*types.AccountInfo) + s.applyGasUpdate(formatAccount) + account, err := chain.FromFormatAccountInfo(formatAccount) + if err != nil { + return err + } + err = s.redisCache.Set(context.Background(), dbcache.AccountKeyByIndex(account.AccountIndex), account) + if err != nil { + return fmt.Errorf("cache to redis failed: %v", err) + } + s.AccountCache.Add(account.AccountIndex, formatAccount) + } + return nil +} + func (s *StateDB) SyncStateCacheToRedis() error { // Sync new create to cache. err := s.syncPendingAccount(s.PendingNewAccountMap) @@ -287,15 +305,58 @@ func (s *StateDB) GetPendingAccount(blockHeight int64) ([]*account.Account, []*a }) } + gasChanged := false + for _, delta := range s.StateCache.PendingGasMap { + if delta.Cmp(types.ZeroBigInt) > 0 { + gasChanged = true + break + } + } + + handledGasAccount := false for index, formatAccount := range s.PendingUpdateAccountMap { if _, exist := s.PendingNewAccountMap[index]; exist { continue } + if formatAccount.AccountIndex == types.GasAccount && gasChanged { + handledGasAccount = true + s.applyGasUpdate(formatAccount) + } + newAccount, err := chain.FromFormatAccountInfo(formatAccount) if err != nil { return nil, nil, nil, err } + + pendingUpdateAccount = append(pendingUpdateAccount, newAccount) + pendingNewAccountHistory = append(pendingNewAccountHistory, &account.AccountHistory{ + AccountIndex: newAccount.AccountIndex, + Nonce: newAccount.Nonce, + CollectionNonce: newAccount.CollectionNonce, + AssetInfo: newAccount.AssetInfo, + AssetRoot: newAccount.AssetRoot, + L2BlockHeight: blockHeight, // TODO: ensure this should be the new block's height. + }) + } + + if !handledGasAccount && gasChanged { + gasAccount, err := s.GetAccount(types.GasAccount) + if err != nil { + return nil, nil, nil, err + } + + formatAccount, err := chain.ToFormatAccountInfo(gasAccount) + if err != nil { + return nil, nil, nil, err + } + s.applyGasUpdate(formatAccount) + + newAccount, err := chain.FromFormatAccountInfo(formatAccount) + if err != nil { + return nil, nil, nil, err + } + pendingUpdateAccount = append(pendingUpdateAccount, newAccount) pendingNewAccountHistory = append(pendingNewAccountHistory, &account.AccountHistory{ AccountIndex: newAccount.AccountIndex, @@ -310,6 +371,19 @@ func (s *StateDB) GetPendingAccount(blockHeight int64) ([]*account.Account, []*a return pendingNewAccount, pendingUpdateAccount, pendingNewAccountHistory, nil } +func (s *StateDB) applyGasUpdate(formatAccount *types.AccountInfo) { + for assetId, delta := range s.StateCache.PendingGasMap { + if asset, ok := formatAccount.AssetInfo[assetId]; ok { + formatAccount.AssetInfo[assetId].Balance = ffmath.Add(asset.Balance, delta) + } else { + formatAccount.AssetInfo[assetId] = &types.AccountAsset{ + Balance: delta, + OfferCanceledOrFinalized: types.ZeroBigInt, + } + } + } +} + func (s *StateDB) GetPendingNft(blockHeight int64) ([]*nft.L2Nft, []*nft.L2Nft, []*nft.L2NftHistory, error) { pendingNewNft := make([]*nft.L2Nft, 0) pendingUpdateNft := make([]*nft.L2Nft, 0) @@ -365,11 +439,7 @@ func (s *StateDB) DeepCopyAccounts(accountIds []int64) (map[int64]*types.Account if err != nil { return nil, err } - accountCopy, err := account.DeepCopy() - if err != nil { - return nil, err - } - accounts[accountId] = accountCopy + accounts[accountId] = account.DeepCopy() } return accounts, nil @@ -465,9 +535,23 @@ func (s *StateDB) updateAccountTree(accountIndex int64, assets []int64) error { if err != nil { return err } + isGasAccount := accountIndex == types.GasAccount for _, assetId := range assets { + isGasAsset := false + if isGasAccount { + for _, gasAssetId := range types.GasAssets { + if assetId == gasAssetId { + isGasAsset = true + break + } + } + } + balance := account.AssetInfo[assetId].Balance + if isGasAsset { + balance = ffmath.Add(balance, s.GetPendingUpdateGas(assetId)) + } assetLeaf, err := tree.ComputeAccountAssetLeafHash( - account.AssetInfo[assetId].Balance.String(), + balance.String(), account.AssetInfo[assetId].OfferCanceledOrFinalized.String(), ) if err != nil { diff --git a/dao/account/account_history.go b/dao/account/account_history.go index 52ea69cd1..8024854ef 100644 --- a/dao/account/account_history.go +++ b/dao/account/account_history.go @@ -33,6 +33,7 @@ type ( GetValidAccounts(height int64, limit int, offset int) (rowsAffected int64, accounts []*AccountHistory, err error) GetValidAccountCount(height int64) (accounts int64, err error) CreateAccountHistoriesInTransact(tx *gorm.DB, histories []*AccountHistory) error + GetLatestAccountHistory(accountIndex, height int64) (accountHistory *AccountHistory, err error) } defaultAccountHistoryModel struct { @@ -47,7 +48,7 @@ type ( CollectionNonce int64 AssetInfo string AssetRoot string - L2BlockHeight int64 + L2BlockHeight int64 `gorm:"index"` } ) @@ -120,3 +121,13 @@ func (m *defaultAccountHistoryModel) CreateAccountHistoriesInTransact(tx *gorm.D } return nil } + +func (m *defaultAccountHistoryModel) GetLatestAccountHistory(accountIndex, height int64) (accountHistory *AccountHistory, err error) { + dbTx := m.DB.Table(m.table).Where("account_index = ? and l2_block_height < ?", accountIndex, height).Order("l2_block_height desc").Limit(1).Find(&accountHistory) + if dbTx.Error != nil { + return nil, types.DbErrSqlOperation + } else if dbTx.RowsAffected == 0 { + return nil, types.DbErrNotFound + } + return accountHistory, nil +} diff --git a/dao/tx/tx_detail.go b/dao/tx/tx_detail.go index 61562d3ca..04510e134 100644 --- a/dao/tx/tx_detail.go +++ b/dao/tx/tx_detail.go @@ -47,6 +47,7 @@ type ( AccountOrder int64 Nonce int64 CollectionNonce int64 + IsGas bool `gorm:"default:false"` } ) diff --git a/deploy-qa.sh b/deploy-qa.sh index 8135b285d..7ca06dc6a 100644 --- a/deploy-qa.sh +++ b/deploy-qa.sh @@ -218,6 +218,7 @@ ChainConfig: MaxBlockCount: 4 Sk: "acbaa269bd7573ff12361be4b97201aef019776ea13384681d4e5ba6a88367d9" GasLimit: 5000000 + GasPrice: 0 TreeDB: Driver: memorydb diff --git a/go.mod b/go.mod index 6101dbd2d..d3af2f2e5 100644 --- a/go.mod +++ b/go.mod @@ -90,7 +90,7 @@ require ( ) require ( - github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220930094817-c69f57d0225b + github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221009123206-1971dadf3584 github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f github.com/consensys/gnark v0.7.0 @@ -106,7 +106,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.2 // indirect golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6 // indirect + golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect google.golang.org/grpc v1.46.2 // indirect google.golang.org/protobuf v1.28.0 // indirect gorm.io/driver/postgres v1.3.6 diff --git a/go.sum b/go.sum index 81fd17466..d670645b8 100644 --- a/go.sum +++ b/go.sum @@ -117,8 +117,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220930094817-c69f57d0225b h1:LZds9MhqLIQde7VMN/Z8gocVZ+BOknV0TCy2TIqUnKE= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20220930094817-c69f57d0225b/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221009123206-1971dadf3584 h1:CnKNWgM6qJC3nlOeyw4ILLkbih83VkHnSdLbY5stK3M= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221009123206-1971dadf3584/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 h1:1rMa8XpplDNZaxeM1ifXMjSSeH/ucJyLUjHHEw1z4AA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2/go.mod h1:T69T8enicQ5kSRPIzyPJv/jhuvRMz1UxsijPXmlis+I= github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f h1:zBVWOWlH4w18O6wp0gZML4U2n1rxsFLb7KB7DFE8zcQ= @@ -1199,8 +1199,9 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6 h1:cy1ko5847T/lJ45eyg/7uLprIE/amW5IXxGtEnQdYMI= golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 h1:AzgQNqF+FKwyQ5LbVrVqOcuuFB67N47F9+htZYH0wFM= +golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/service/committer/committer/committer.go b/service/committer/committer/committer.go index d3027e31f..ebc0ad6fe 100644 --- a/service/committer/committer/committer.go +++ b/service/committer/committer/committer.go @@ -22,12 +22,12 @@ const ( var ( priorityOperationMetric = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "zkbnb", - Name: "prioriry_operation_process", + Name: "priority_operation_process", Help: "Priority operation requestID metrics.", }) priorityOperationHeightMetric = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "zkbnb", - Name: "prioriry_operation_process_height", + Name: "priority_operation_process_height", Help: "Priority operation height metrics.", }) ) @@ -260,6 +260,11 @@ func (c *Committer) commitNewBlock(curBlock *block.Block) (*block.Block, error) return nil, err } + err = c.bc.Statedb.SyncPendingGasAccount() + if err != nil { + return nil, err + } + // update db err = c.bc.DB().DB.Transaction(func(tx *gorm.DB) error { // create block for commit @@ -320,7 +325,6 @@ func (c *Committer) commitNewBlock(curBlock *block.Block) (*block.Block, error) blockStates.Block.ClearTxsModel() return c.bc.DB().BlockModel.UpdateBlockInTransact(tx, blockStates.Block) }) - if err != nil { return nil, err } diff --git a/service/monitor/monitor/monitor.go b/service/monitor/monitor/monitor.go index 65152f86c..840889a9d 100644 --- a/service/monitor/monitor/monitor.go +++ b/service/monitor/monitor/monitor.go @@ -40,13 +40,13 @@ import ( var ( priorityOperationMetric = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "zkbnb", - Name: "prioriry_operation_insert", + Name: "priority_operation_insert", Help: "Priority operation requestID metrics.", }) priorityOperationHeightMetric = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: "zkbnb", - Name: "prioriry_operation_insert_height", + Name: "priority_operation_insert_height", Help: "Priority operation height metrics.", }) ) diff --git a/service/prover/prover/prover.go b/service/prover/prover/prover.go index 11d13f337..d250719b4 100644 --- a/service/prover/prover/prover.go +++ b/service/prover/prover/prover.go @@ -82,6 +82,10 @@ func NewProver(c config.Config) *Prover { for i := 0; i < blockConstraints.TxsCount; i++ { blockConstraints.Txs[i] = circuit.GetZeroTxConstraint() } + blockConstraints.GasAssetIds = types.GasAssets[:] + blockConstraints.GasAccountIndex = types.GasAccount + blockConstraints.Gas = circuit.GetZeroGasConstraints(types.GasAssets[:]) + logx.Infof("start compile block size %d blockConstraints", blockConstraints.TxsCount) prover.R1cs[i], err = frontend.Compile(ecc.BN254, r1cs.NewBuilder, &blockConstraints, frontend.IgnoreUnconstrainedInputs()) if err != nil { diff --git a/service/witness/witness/witness.go b/service/witness/witness/witness.go index 1a4304c47..e770e55d2 100644 --- a/service/witness/witness/witness.go +++ b/service/witness/witness/witness.go @@ -123,7 +123,7 @@ func (w *Witness) initState() error { return err } w.taskPool = taskPool - w.helper = utils.NewWitnessHelper(w.treeCtx, w.accountTree, w.nftTree, w.assetTrees, w.accountModel) + w.helper = utils.NewWitnessHelper(w.treeCtx, w.accountTree, w.nftTree, w.assetTrees, w.accountModel, w.accountHistoryModel) return nil } @@ -243,6 +243,10 @@ func (w *Witness) constructBlockWitness(block *block.Block, latestVerifiedBlockN var oldStateRoot, newStateRoot []byte txsWitness := make([]*utils.TxWitness, 0, block.BlockSize) // scan each transaction + err := w.helper.ResetCache(block.BlockHeight) + if err != nil { + return nil, err + } for idx, tx := range block.Txs { txWitness, err := w.helper.ConstructTxWitness(tx, uint64(latestVerifiedBlockNr)) if err != nil { @@ -263,6 +267,13 @@ func (w *Witness) constructBlockWitness(block *block.Block, latestVerifiedBlockN for i := 0; i < emptyTxCount; i++ { txsWitness = append(txsWitness, circuit.EmptyTx(newStateRoot)) } + + gasWitness, err := w.helper.ConstructGasWitness(block) + if err != nil { + return nil, err + } + + newStateRoot = tree.ComputeStateRootHash(w.accountTree.Root(), w.nftTree.Root()) if common.Bytes2Hex(newStateRoot) != block.StateRoot { return nil, errors.New("state root doesn't match") } @@ -274,6 +285,7 @@ func (w *Witness) constructBlockWitness(block *block.Block, latestVerifiedBlockN NewStateRoot: newStateRoot, BlockCommitment: common.FromHex(block.BlockCommitment), Txs: txsWitness, + Gas: gasWitness, } bz, err := json.Marshal(b) if err != nil { diff --git a/tree/asset_tree_cache.go b/tree/asset_tree_cache.go index 7ec8cae73..22b735200 100644 --- a/tree/asset_tree_cache.go +++ b/tree/asset_tree_cache.go @@ -3,8 +3,9 @@ package tree import ( "sync" - bsmt "github.com/bnb-chain/zkbnb-smt" lru "github.com/hashicorp/golang-lru" + + bsmt "github.com/bnb-chain/zkbnb-smt" ) // Lazy init cache for asset trees diff --git a/types/account.go b/types/account.go index 269ae1de9..ecf6f2a79 100644 --- a/types/account.go +++ b/types/account.go @@ -80,7 +80,7 @@ type AccountInfo struct { Status int } -func (ai *AccountInfo) DeepCopy() (*AccountInfo, error) { +func (ai *AccountInfo) DeepCopy() *AccountInfo { assetInfo := make(map[int64]*AccountAsset) for assetId, asset := range ai.AssetInfo { assetInfo[assetId] = asset.DeepCopy() @@ -99,5 +99,5 @@ func (ai *AccountInfo) DeepCopy() (*AccountInfo, error) { AssetRoot: ai.AssetRoot, Status: ai.Status, } - return newAccountInfo, nil + return newAccountInfo } diff --git a/types/constant.go b/types/constant.go index 7254c87bb..6a9f375ff 100644 --- a/types/constant.go +++ b/types/constant.go @@ -45,9 +45,11 @@ const ( NilExpiredAt = math.MaxInt64 NilAssetAmount = "0" + GasAccount = int64(1) BNBAssetId = 0 ) var ( EmptyOfferCanceledOrFinalized = big.NewInt(0) + GasAssets = [2]int64{0, 1} ) From c10d96ed95808b0c19901d744cd71cc9cd7b05ee Mon Sep 17 00:00:00 2001 From: yutianwu Date: Wed, 12 Oct 2022 16:22:58 +0800 Subject: [PATCH 19/23] refactor: reduce public inputs of block constraints (#218) * refactor: reduce public inputs of block contraints * update dependency * fix conflict --- go.mod | 2 +- go.sum | 4 ++-- service/prover/verifier_parse.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index d3af2f2e5..78dca50e4 100644 --- a/go.mod +++ b/go.mod @@ -90,7 +90,7 @@ require ( ) require ( - github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221009123206-1971dadf3584 + github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221012064947-a395ff5a2614 github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f github.com/consensys/gnark v0.7.0 diff --git a/go.sum b/go.sum index d670645b8..ad3f85230 100644 --- a/go.sum +++ b/go.sum @@ -117,8 +117,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221009123206-1971dadf3584 h1:CnKNWgM6qJC3nlOeyw4ILLkbih83VkHnSdLbY5stK3M= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221009123206-1971dadf3584/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221012064947-a395ff5a2614 h1:a+POfow+uc60upenBUrzo9XW/nk7H9llv45UVdF67xw= +github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221012064947-a395ff5a2614/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 h1:1rMa8XpplDNZaxeM1ifXMjSSeH/ucJyLUjHHEw1z4AA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2/go.mod h1:T69T8enicQ5kSRPIzyPJv/jhuvRMz1UxsijPXmlis+I= github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f h1:zBVWOWlH4w18O6wp0gZML4U2n1rxsFLb7KB7DFE8zcQ= diff --git a/service/prover/verifier_parse.py b/service/prover/verifier_parse.py index 67d817f56..e220a1a7e 100644 --- a/service/prover/verifier_parse.py +++ b/service/prover/verifier_parse.py @@ -43,7 +43,7 @@ def find_and_delete_func(func_name, lines): lines = f.readlines() for nu in range(len(lines)): if lines[nu].count("function verifyingKey()"): - for i in range(8): + for i in range(6): tmp = lines[nu + 1 + i].split("uint256") for j in range(len(tmp) - 1): vks.append("".join([x for x in tmp[j+1] if x.isdigit()])) @@ -78,8 +78,8 @@ def find_and_delete_func(func_name, lines): new_lines.append(" if (block_size == " + src_block_sizes[i] + ") {\n") else: new_lines.append(" } else if (block_size == " + src_block_sizes[i] + ") {\n") - new_lines.append(" gammaABC = new uint256[](8);\n") - for j in range(8): + new_lines.append(" gammaABC = new uint256[](4);\n") + for j in range(4): new_lines.append(" gammaABC[" + str(j) + "] = " + all_vks[i][14 + j] + ";\n") new_lines.append(" return gammaABC;\n") new_lines.append(" } else {\n") @@ -101,4 +101,4 @@ def find_and_delete_func(func_name, lines): print(lines[nu + 2 + i]) """ with open(dest_filename, "w") as f: - f.writelines(update_lines) + f.writelines(update_lines) \ No newline at end of file From a51fdc25048339243b76923c92ff4dc6f1beb90b Mon Sep 17 00:00:00 2001 From: KeefeL <90749943+KeefeL@users.noreply.github.com> Date: Wed, 12 Oct 2022 17:54:46 +0800 Subject: [PATCH 20/23] core, dao: merge new update map for account and nft (#219) --- core/blockchain.go | 18 +-- core/executor/atomic_match_executor.go | 10 +- core/executor/cancel_offer_executor.go | 2 +- core/executor/create_collection_executor.go | 2 +- core/executor/deposit_executor.go | 28 +--- core/executor/deposit_nft_executor.go | 28 +--- core/executor/full_exit_executor.go | 28 +--- core/executor/full_exit_nft_executor.go | 28 +--- core/executor/mint_nft_executor.go | 4 +- core/executor/register_zns_executor.go | 17 +-- core/executor/transfer_executor.go | 4 +- core/executor/transfer_nft_executor.go | 4 +- core/executor/withdraw_executor.go | 2 +- core/executor/withdraw_nft_executor.go | 4 +- core/statedb/state_cache.go | 54 ++----- core/statedb/statedb.go | 158 ++++++++++---------- dao/account/account.go | 12 -- dao/block/block.go | 10 +- dao/nft/nft.go | 12 -- service/committer/committer/committer.go | 38 ++--- 20 files changed, 142 insertions(+), 321 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 7416ed80e..88676ac27 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -169,25 +169,23 @@ func (bc *BlockChain) CommitNewBlock(blockSize int, createdAt int64) (*block.Blo return nil, err } - pendingNewAccount, pendingUpdateAccount, pendingNewAccountHistory, err := bc.Statedb.GetPendingAccount(currentHeight) + pendingAccount, pendingAccountHistory, err := bc.Statedb.GetPendingAccount(currentHeight) if err != nil { return nil, err } - pendingNewNft, pendingUpdateNft, pendingNewNftHistory, err := bc.Statedb.GetPendingNft(currentHeight) + pendingNft, pendingNftHistory, err := bc.Statedb.GetPendingNft(currentHeight) if err != nil { return nil, err } return &block.BlockStates{ - Block: newBlock, - CompressedBlock: compressedBlock, - PendingNewAccount: pendingNewAccount, - PendingUpdateAccount: pendingUpdateAccount, - PendingNewAccountHistory: pendingNewAccountHistory, - PendingNewNft: pendingNewNft, - PendingUpdateNft: pendingUpdateNft, - PendingNewNftHistory: pendingNewNftHistory, + Block: newBlock, + CompressedBlock: compressedBlock, + PendingAccount: pendingAccount, + PendingAccountHistory: pendingAccountHistory, + PendingNft: pendingNft, + PendingNftHistory: pendingNftHistory, }, nil } diff --git a/core/executor/atomic_match_executor.go b/core/executor/atomic_match_executor.go index 52d69932c..95a1d5e28 100644 --- a/core/executor/atomic_match_executor.go +++ b/core/executor/atomic_match_executor.go @@ -215,11 +215,11 @@ func (e *AtomicMatchExecutor) ApplyTransaction() error { matchNft.OwnerAccountIndex = txInfo.BuyOffer.AccountIndex stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(fromAccount.AccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(buyAccount.AccountIndex, buyAccount) - stateCache.SetPendingUpdateAccount(sellAccount.AccountIndex, sellAccount) - stateCache.SetPendingUpdateAccount(creatorAccount.AccountIndex, creatorAccount) - stateCache.SetPendingUpdateNft(matchNft.NftIndex, matchNft) + stateCache.SetPendingAccount(fromAccount.AccountIndex, fromAccount) + stateCache.SetPendingAccount(buyAccount.AccountIndex, buyAccount) + stateCache.SetPendingAccount(sellAccount.AccountIndex, sellAccount) + stateCache.SetPendingAccount(creatorAccount.AccountIndex, creatorAccount) + stateCache.SetPendingNft(matchNft.NftIndex, matchNft) stateCache.SetPendingUpdateGas(txInfo.BuyOffer.AssetId, txInfo.TreasuryAmount) stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() diff --git a/core/executor/cancel_offer_executor.go b/core/executor/cancel_offer_executor.go index 05838f03b..3ab06ba4a 100644 --- a/core/executor/cancel_offer_executor.go +++ b/core/executor/cancel_offer_executor.go @@ -93,7 +93,7 @@ func (e *CancelOfferExecutor) ApplyTransaction() error { fromAccount.AssetInfo[offerAssetId].OfferCanceledOrFinalized = nOffer stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(fromAccount.AccountIndex, fromAccount) + stateCache.SetPendingAccount(fromAccount.AccountIndex, fromAccount) stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/create_collection_executor.go b/core/executor/create_collection_executor.go index b185ff4ff..8fbf28464 100644 --- a/core/executor/create_collection_executor.go +++ b/core/executor/create_collection_executor.go @@ -88,7 +88,7 @@ func (e *CreateCollectionExecutor) ApplyTransaction() error { fromAccount.CollectionNonce++ stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(fromAccount.AccountIndex, fromAccount) + stateCache.SetPendingAccount(fromAccount.AccountIndex, fromAccount) stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/deposit_executor.go b/core/executor/deposit_executor.go index 72aac9aec..46ef44eed 100644 --- a/core/executor/deposit_executor.go +++ b/core/executor/deposit_executor.go @@ -41,31 +41,9 @@ func (e *DepositExecutor) Prepare() error { // The account index from txInfo isn't true, find account by account name hash. accountNameHash := common.Bytes2Hex(txInfo.AccountNameHash) - account, err := bc.DB().AccountModel.GetAccountByNameHash(accountNameHash) + account, err := bc.StateDB().GetAccountByNameHash(accountNameHash) if err != nil { - exist := false - var newAccountIndexes []int64 - for index := range bc.StateDB().PendingNewAccountMap { - newAccountIndexes = append(newAccountIndexes, index) - } - for index := range bc.StateDB().PendingUpdateAccountMap { - newAccountIndexes = append(newAccountIndexes, index) - } - for _, index := range newAccountIndexes { - tempAccount, err := bc.StateDB().GetAccount(index) - if err != nil { - continue - } - if accountNameHash == tempAccount.AccountNameHash { - account = tempAccount - exist = true - break - } - } - - if !exist { - return errors.New("invalid account name hash") - } + return err } // Set the right account index. @@ -97,7 +75,7 @@ func (e *DepositExecutor) ApplyTransaction() error { depositAccount.AssetInfo[txInfo.AssetId].Balance = ffmath.Add(depositAccount.AssetInfo[txInfo.AssetId].Balance, txInfo.AssetAmount) stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(depositAccount.AccountIndex, depositAccount) + stateCache.SetPendingAccount(depositAccount.AccountIndex, depositAccount) return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/deposit_nft_executor.go b/core/executor/deposit_nft_executor.go index be818d13c..c5b502f53 100644 --- a/core/executor/deposit_nft_executor.go +++ b/core/executor/deposit_nft_executor.go @@ -41,31 +41,9 @@ func (e *DepositNftExecutor) Prepare() error { // The account index from txInfo isn't true, find account by account name hash. accountNameHash := common.Bytes2Hex(txInfo.AccountNameHash) - account, err := bc.DB().AccountModel.GetAccountByNameHash(accountNameHash) + account, err := bc.StateDB().GetAccountByNameHash(accountNameHash) if err != nil { - exist := false - var newAccountIndexes []int64 - for index := range bc.StateDB().PendingNewAccountMap { - newAccountIndexes = append(newAccountIndexes, index) - } - for index := range bc.StateDB().PendingUpdateAccountMap { - newAccountIndexes = append(newAccountIndexes, index) - } - for _, index := range newAccountIndexes { - tempAccount, err := bc.StateDB().GetAccount(index) - if err != nil { - continue - } - if accountNameHash == tempAccount.AccountNameHash { - account = tempAccount - exist = true - break - } - } - - if !exist { - return errors.New("invalid account name hash") - } + return err } // Set the right account index. @@ -113,7 +91,7 @@ func (e *DepositNftExecutor) ApplyTransaction() error { } stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateNft(txInfo.NftIndex, nft) + stateCache.SetPendingNft(txInfo.NftIndex, nft) return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/full_exit_executor.go b/core/executor/full_exit_executor.go index fed7a0f76..1215b567b 100644 --- a/core/executor/full_exit_executor.go +++ b/core/executor/full_exit_executor.go @@ -41,31 +41,9 @@ func (e *FullExitExecutor) Prepare() error { // The account index from txInfo isn't true, find account by account name hash. accountNameHash := common.Bytes2Hex(txInfo.AccountNameHash) - account, err := bc.DB().AccountModel.GetAccountByNameHash(accountNameHash) + account, err := bc.StateDB().GetAccountByNameHash(accountNameHash) if err != nil { - exist := false - var newAccountIndexes []int64 - for index := range bc.StateDB().PendingNewAccountMap { - newAccountIndexes = append(newAccountIndexes, index) - } - for index := range bc.StateDB().PendingUpdateAccountMap { - newAccountIndexes = append(newAccountIndexes, index) - } - for _, index := range newAccountIndexes { - tempAccount, err := bc.StateDB().GetAccount(index) - if err != nil { - continue - } - if accountNameHash == tempAccount.AccountNameHash { - account = tempAccount - exist = true - break - } - } - - if !exist { - return errors.New("invalid account name hash") - } + return err } // Set the right account index. @@ -103,7 +81,7 @@ func (e *FullExitExecutor) ApplyTransaction() error { if txInfo.AssetAmount.Cmp(types.ZeroBigInt) != 0 { stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(txInfo.AccountIndex, exitAccount) + stateCache.SetPendingAccount(txInfo.AccountIndex, exitAccount) } return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/full_exit_nft_executor.go b/core/executor/full_exit_nft_executor.go index 7cf5eefe1..30586cdb3 100644 --- a/core/executor/full_exit_nft_executor.go +++ b/core/executor/full_exit_nft_executor.go @@ -44,31 +44,9 @@ func (e *FullExitNftExecutor) Prepare() error { // The account index from txInfo isn't true, find account by account name hash. accountNameHash := common.Bytes2Hex(txInfo.AccountNameHash) - account, err := bc.DB().AccountModel.GetAccountByNameHash(accountNameHash) + account, err := bc.StateDB().GetAccountByNameHash(accountNameHash) if err != nil { - exist := false - var newAccountIndexes []int64 - for index := range bc.StateDB().PendingNewAccountMap { - newAccountIndexes = append(newAccountIndexes, index) - } - for index := range bc.StateDB().PendingUpdateAccountMap { - newAccountIndexes = append(newAccountIndexes, index) - } - for _, index := range newAccountIndexes { - tempAccount, err := bc.StateDB().GetAccount(index) - if err != nil { - continue - } - if accountNameHash == tempAccount.AccountNameHash { - account = tempAccount - exist = true - break - } - } - - if !exist { - return errors.New("invalid account name hash") - } + return err } // Set the right account index. @@ -154,7 +132,7 @@ func (e *FullExitNftExecutor) ApplyTransaction() error { } stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateNft(txInfo.NftIndex, emptyNft) + stateCache.SetPendingNft(txInfo.NftIndex, emptyNft) return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/mint_nft_executor.go b/core/executor/mint_nft_executor.go index 7324e8bd0..5fd85c3da 100644 --- a/core/executor/mint_nft_executor.go +++ b/core/executor/mint_nft_executor.go @@ -94,8 +94,8 @@ func (e *MintNftExecutor) ApplyTransaction() error { creatorAccount.Nonce++ stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(txInfo.CreatorAccountIndex, creatorAccount) - stateCache.SetPendingNewNft(txInfo.NftIndex, &nft.L2Nft{ + stateCache.SetPendingAccount(txInfo.CreatorAccountIndex, creatorAccount) + stateCache.SetPendingNft(txInfo.NftIndex, &nft.L2Nft{ NftIndex: txInfo.NftIndex, CreatorAccountIndex: txInfo.CreatorAccountIndex, OwnerAccountIndex: txInfo.ToAccountIndex, diff --git a/core/executor/register_zns_executor.go b/core/executor/register_zns_executor.go index 31994e79a..a381119dd 100644 --- a/core/executor/register_zns_executor.go +++ b/core/executor/register_zns_executor.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/zeromicro/go-zero/core/logx" - "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/bnb-chain/zkbnb-crypto/wasm/txtypes" common2 "github.com/bnb-chain/zkbnb/common" @@ -52,21 +51,11 @@ func (e *RegisterZnsExecutor) VerifyInputs(skipGasAmtChk bool) error { bc := e.bc txInfo := e.txInfo - _, err := bc.DB().AccountModel.GetAccountByName(txInfo.AccountName) - if err != sqlx.ErrNotFound { + _, err := bc.StateDB().GetAccountByName(txInfo.AccountName) + if err == nil { return errors.New("invalid account name, already registered") } - for index := range bc.StateDB().PendingNewAccountMap { - account, err := bc.StateDB().GetFormatAccount(index) - if err != nil { - continue - } - if txInfo.AccountName == account.AccountName { - return errors.New("invalid account name, already registered") - } - } - if txInfo.AccountIndex != bc.StateDB().GetNextAccountIndex() { return errors.New("invalid account index") } @@ -99,7 +88,7 @@ func (e *RegisterZnsExecutor) ApplyTransaction() error { bc.StateDB().AccountAssetTrees.UpdateCache(txInfo.AccountIndex, bc.CurrentBlock().BlockHeight) stateCache := e.bc.StateDB() - stateCache.SetPendingNewAccount(txInfo.AccountIndex, formatAccount) + stateCache.SetPendingAccount(txInfo.AccountIndex, formatAccount) return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/transfer_executor.go b/core/executor/transfer_executor.go index 3956f0559..887df5e5f 100644 --- a/core/executor/transfer_executor.go +++ b/core/executor/transfer_executor.go @@ -99,8 +99,8 @@ func (e *TransferExecutor) ApplyTransaction() error { fromAccount.Nonce++ stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(txInfo.FromAccountIndex, fromAccount) - stateCache.SetPendingUpdateAccount(txInfo.ToAccountIndex, toAccount) + stateCache.SetPendingAccount(txInfo.FromAccountIndex, fromAccount) + stateCache.SetPendingAccount(txInfo.ToAccountIndex, toAccount) stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/transfer_nft_executor.go b/core/executor/transfer_nft_executor.go index 7da602fb2..27a4fe157 100644 --- a/core/executor/transfer_nft_executor.go +++ b/core/executor/transfer_nft_executor.go @@ -103,8 +103,8 @@ func (e *TransferNftExecutor) ApplyTransaction() error { nft.OwnerAccountIndex = txInfo.ToAccountIndex stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(txInfo.FromAccountIndex, fromAccount) - stateCache.SetPendingUpdateNft(txInfo.NftIndex, nft) + stateCache.SetPendingAccount(txInfo.FromAccountIndex, fromAccount) + stateCache.SetPendingNft(txInfo.NftIndex, nft) stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/withdraw_executor.go b/core/executor/withdraw_executor.go index 596fd5fbf..793218caf 100644 --- a/core/executor/withdraw_executor.go +++ b/core/executor/withdraw_executor.go @@ -86,7 +86,7 @@ func (e *WithdrawExecutor) ApplyTransaction() error { fromAccount.Nonce++ stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(txInfo.FromAccountIndex, fromAccount) + stateCache.SetPendingAccount(txInfo.FromAccountIndex, fromAccount) stateCache.SetPendingUpdateGas(txInfo.GasFeeAssetId, txInfo.GasFeeAssetAmount) return e.BaseExecutor.ApplyTransaction() } diff --git a/core/executor/withdraw_nft_executor.go b/core/executor/withdraw_nft_executor.go index cd5797474..dc62c1008 100644 --- a/core/executor/withdraw_nft_executor.go +++ b/core/executor/withdraw_nft_executor.go @@ -122,8 +122,8 @@ func (e *WithdrawNftExecutor) ApplyTransaction() error { newNftInfo := types.EmptyNftInfo(txInfo.NftIndex) stateCache := e.bc.StateDB() - stateCache.SetPendingUpdateAccount(txInfo.AccountIndex, fromAccount) - stateCache.SetPendingUpdateNft(txInfo.NftIndex, &nft.L2Nft{ + stateCache.SetPendingAccount(txInfo.AccountIndex, fromAccount) + stateCache.SetPendingNft(txInfo.NftIndex, &nft.L2Nft{ Model: oldNft.Model, NftIndex: newNftInfo.NftIndex, CreatorAccountIndex: newNftInfo.CreatorAccountIndex, diff --git a/core/statedb/state_cache.go b/core/statedb/state_cache.go index cf5c61c9f..8b28ece3f 100644 --- a/core/statedb/state_cache.go +++ b/core/statedb/state_cache.go @@ -23,11 +23,9 @@ type StateCache struct { Txs []*tx.Tx // Record the flat data that should be updated. - PendingNewAccountMap map[int64]*types.AccountInfo - PendingNewNftMap map[int64]*nft.L2Nft - PendingUpdateAccountMap map[int64]*types.AccountInfo - PendingUpdateNftMap map[int64]*nft.L2Nft - PendingGasMap map[int64]*big.Int //pending gas changes of a block + PendingAccountMap map[int64]*types.AccountInfo + PendingNftMap map[int64]*nft.L2Nft + PendingGasMap map[int64]*big.Int //pending gas changes of a block // Record the tree states that should be updated. dirtyAccountsAndAssetsMap map[int64]map[int64]bool @@ -39,11 +37,9 @@ func NewStateCache(stateRoot string) *StateCache { StateRoot: stateRoot, Txs: make([]*tx.Tx, 0), - PendingNewAccountMap: make(map[int64]*types.AccountInfo, 0), - PendingNewNftMap: make(map[int64]*nft.L2Nft, 0), - PendingUpdateAccountMap: make(map[int64]*types.AccountInfo, 0), - PendingUpdateNftMap: make(map[int64]*nft.L2Nft, 0), - PendingGasMap: make(map[int64]*big.Int, 0), + PendingAccountMap: make(map[int64]*types.AccountInfo, 0), + PendingNftMap: make(map[int64]*nft.L2Nft, 0), + PendingGasMap: make(map[int64]*big.Int, 0), PubData: make([]byte, 0), PriorityOperations: 0, @@ -84,11 +80,7 @@ func (c *StateCache) MarkNftDirty(nftIndex int64) { } func (c *StateCache) GetPendingAccount(accountIndex int64) (*types.AccountInfo, bool) { - account, exist := c.PendingNewAccountMap[accountIndex] - if exist { - return account, exist - } - account, exist = c.PendingUpdateAccountMap[accountIndex] + account, exist := c.PendingAccountMap[accountIndex] if exist { return account, exist } @@ -96,41 +88,19 @@ func (c *StateCache) GetPendingAccount(accountIndex int64) (*types.AccountInfo, } func (c *StateCache) GetPendingNft(nftIndex int64) (*nft.L2Nft, bool) { - nft, exist := c.PendingNewNftMap[nftIndex] - if exist { - return nft, exist - } - nft, exist = c.PendingUpdateNftMap[nftIndex] + nft, exist := c.PendingNftMap[nftIndex] if exist { return nft, exist } return nil, false } -func (c *StateCache) SetPendingNewAccount(accountIndex int64, account *types.AccountInfo) { - c.PendingNewAccountMap[accountIndex] = account -} - -func (c *StateCache) SetPendingUpdateAccount(accountIndex int64, account *types.AccountInfo) { - // TO confirm: why need a separate PendingNewAccount Map - _, exist := c.PendingNewAccountMap[accountIndex] - if exist { - delete(c.PendingNewAccountMap, accountIndex) - } - c.PendingUpdateAccountMap[accountIndex] = account +func (c *StateCache) SetPendingAccount(accountIndex int64, account *types.AccountInfo) { + c.PendingAccountMap[accountIndex] = account } -func (c *StateCache) SetPendingNewNft(nftIndex int64, nft *nft.L2Nft) { - c.PendingNewNftMap[nftIndex] = nft -} - -func (c *StateCache) SetPendingUpdateNft(nftIndex int64, nft *nft.L2Nft) { - // TO confirm: why need a separate PendingNewAccount Map - _, exist := c.PendingNewNftMap[nftIndex] - if exist { - delete(c.PendingNewNftMap, nftIndex) - } - c.PendingUpdateNftMap[nftIndex] = nft +func (c *StateCache) SetPendingNft(nftIndex int64, nft *nft.L2Nft) { + c.PendingNftMap[nftIndex] = nft } func (c *StateCache) GetPendingUpdateGas(assetId int64) *big.Int { diff --git a/core/statedb/statedb.go b/core/statedb/statedb.go index 4313bbb6a..b1654211e 100644 --- a/core/statedb/statedb.go +++ b/core/statedb/statedb.go @@ -194,6 +194,54 @@ func (s *StateDB) GetAccount(accountIndex int64) (*account.Account, error) { return account, nil } +// GetAccountByName get the account by its name. +// Firstly, try to find the account in the current state cache, it iterates the pending +// account map, not performance friendly, please take care when use this API. +// Secondly, if not found in the current state cache, then try to find the account from database. +func (s *StateDB) GetAccountByName(accountName string) (*account.Account, error) { + for _, accountInfo := range s.PendingAccountMap { + if accountInfo.AccountName == accountName { + account, err := chain.FromFormatAccountInfo(accountInfo) + if err != nil { + return nil, err + } + + return account, nil + } + } + + account, err := s.chainDb.AccountModel.GetAccountByName(accountName) + if err != nil { + return nil, err + } + + return account, nil +} + +// GetAccountByNameHash get the account by its name hash. +// Firstly, try to find the account in the current state cache, it iterates the pending +// account map, not performance friendly, please take care when use this API. +// Secondly, if not found in the current state cache, then try to find the account from database. +func (s *StateDB) GetAccountByNameHash(accountNameHash string) (*account.Account, error) { + for _, accountInfo := range s.PendingAccountMap { + if accountInfo.AccountNameHash == accountNameHash { + account, err := chain.FromFormatAccountInfo(accountInfo) + if err != nil { + return nil, err + } + + return account, nil + } + } + + account, err := s.chainDb.AccountModel.GetAccountByNameHash(accountNameHash) + if err != nil { + return nil, err + } + + return account, nil +} + func (s *StateDB) GetNft(nftIndex int64) (*nft.L2Nft, error) { pending, exist := s.StateCache.GetPendingNft(nftIndex) if exist { @@ -256,22 +304,12 @@ func (s *StateDB) SyncPendingGasAccount() error { } func (s *StateDB) SyncStateCacheToRedis() error { - // Sync new create to cache. - err := s.syncPendingAccount(s.PendingNewAccountMap) + // Sync pending to cache. + err := s.syncPendingAccount(s.PendingAccountMap) if err != nil { return err } - err = s.syncPendingNft(s.PendingNewNftMap) - if err != nil { - return err - } - - // Sync pending update to cache. - err = s.syncPendingAccount(s.PendingUpdateAccountMap) - if err != nil { - return err - } - err = s.syncPendingNft(s.PendingUpdateNftMap) + err = s.syncPendingNft(s.PendingNftMap) if err != nil { return err } @@ -283,27 +321,9 @@ func (s *StateDB) PurgeCache(stateRoot string) { s.StateCache = NewStateCache(stateRoot) } -func (s *StateDB) GetPendingAccount(blockHeight int64) ([]*account.Account, []*account.Account, []*account.AccountHistory, error) { - pendingNewAccount := make([]*account.Account, 0) - pendingUpdateAccount := make([]*account.Account, 0) - pendingNewAccountHistory := make([]*account.AccountHistory, 0) - - for _, formatAccount := range s.PendingNewAccountMap { - newAccount, err := chain.FromFormatAccountInfo(formatAccount) - if err != nil { - return nil, nil, nil, err - } - - pendingNewAccount = append(pendingNewAccount, newAccount) - pendingNewAccountHistory = append(pendingNewAccountHistory, &account.AccountHistory{ - AccountIndex: newAccount.AccountIndex, - Nonce: newAccount.Nonce, - CollectionNonce: newAccount.CollectionNonce, - AssetInfo: newAccount.AssetInfo, - AssetRoot: newAccount.AssetRoot, - L2BlockHeight: blockHeight, // TODO: ensure this should be the new block's height. - }) - } +func (s *StateDB) GetPendingAccount(blockHeight int64) ([]*account.Account, []*account.AccountHistory, error) { + pendingAccount := make([]*account.Account, 0) + pendingAccountHistory := make([]*account.AccountHistory, 0) gasChanged := false for _, delta := range s.StateCache.PendingGasMap { @@ -314,11 +334,7 @@ func (s *StateDB) GetPendingAccount(blockHeight int64) ([]*account.Account, []*a } handledGasAccount := false - for index, formatAccount := range s.PendingUpdateAccountMap { - if _, exist := s.PendingNewAccountMap[index]; exist { - continue - } - + for _, formatAccount := range s.PendingAccountMap { if formatAccount.AccountIndex == types.GasAccount && gasChanged { handledGasAccount = true s.applyGasUpdate(formatAccount) @@ -326,11 +342,10 @@ func (s *StateDB) GetPendingAccount(blockHeight int64) ([]*account.Account, []*a newAccount, err := chain.FromFormatAccountInfo(formatAccount) if err != nil { - return nil, nil, nil, err + return nil, nil, err } - - pendingUpdateAccount = append(pendingUpdateAccount, newAccount) - pendingNewAccountHistory = append(pendingNewAccountHistory, &account.AccountHistory{ + pendingAccount = append(pendingAccount, newAccount) + pendingAccountHistory = append(pendingAccountHistory, &account.AccountHistory{ AccountIndex: newAccount.AccountIndex, Nonce: newAccount.Nonce, CollectionNonce: newAccount.CollectionNonce, @@ -343,22 +358,22 @@ func (s *StateDB) GetPendingAccount(blockHeight int64) ([]*account.Account, []*a if !handledGasAccount && gasChanged { gasAccount, err := s.GetAccount(types.GasAccount) if err != nil { - return nil, nil, nil, err + return nil, nil, err } formatAccount, err := chain.ToFormatAccountInfo(gasAccount) if err != nil { - return nil, nil, nil, err + return nil, nil, err } s.applyGasUpdate(formatAccount) newAccount, err := chain.FromFormatAccountInfo(formatAccount) if err != nil { - return nil, nil, nil, err + return nil, nil, err } - pendingUpdateAccount = append(pendingUpdateAccount, newAccount) - pendingNewAccountHistory = append(pendingNewAccountHistory, &account.AccountHistory{ + pendingAccount = append(pendingAccount, newAccount) + pendingAccountHistory = append(pendingAccountHistory, &account.AccountHistory{ AccountIndex: newAccount.AccountIndex, Nonce: newAccount.Nonce, CollectionNonce: newAccount.CollectionNonce, @@ -368,7 +383,7 @@ func (s *StateDB) GetPendingAccount(blockHeight int64) ([]*account.Account, []*a }) } - return pendingNewAccount, pendingUpdateAccount, pendingNewAccountHistory, nil + return pendingAccount, pendingAccountHistory, nil } func (s *StateDB) applyGasUpdate(formatAccount *types.AccountInfo) { @@ -384,14 +399,13 @@ func (s *StateDB) applyGasUpdate(formatAccount *types.AccountInfo) { } } -func (s *StateDB) GetPendingNft(blockHeight int64) ([]*nft.L2Nft, []*nft.L2Nft, []*nft.L2NftHistory, error) { - pendingNewNft := make([]*nft.L2Nft, 0) - pendingUpdateNft := make([]*nft.L2Nft, 0) - pendingNewNftHistory := make([]*nft.L2NftHistory, 0) +func (s *StateDB) GetPendingNft(blockHeight int64) ([]*nft.L2Nft, []*nft.L2NftHistory, error) { + pendingNft := make([]*nft.L2Nft, 0) + pendingNftHistory := make([]*nft.L2NftHistory, 0) - for _, newNft := range s.PendingNewNftMap { - pendingNewNft = append(pendingNewNft, newNft) - pendingNewNftHistory = append(pendingNewNftHistory, &nft.L2NftHistory{ + for _, newNft := range s.PendingNftMap { + pendingNft = append(pendingNft, newNft) + pendingNftHistory = append(pendingNftHistory, &nft.L2NftHistory{ NftIndex: newNft.NftIndex, CreatorAccountIndex: newNft.CreatorAccountIndex, OwnerAccountIndex: newNft.OwnerAccountIndex, @@ -404,25 +418,7 @@ func (s *StateDB) GetPendingNft(blockHeight int64) ([]*nft.L2Nft, []*nft.L2Nft, }) } - for index, newNft := range s.PendingUpdateNftMap { - if _, exist := s.PendingNewNftMap[index]; exist { - continue - } - pendingUpdateNft = append(pendingUpdateNft, newNft) - pendingNewNftHistory = append(pendingNewNftHistory, &nft.L2NftHistory{ - NftIndex: newNft.NftIndex, - CreatorAccountIndex: newNft.CreatorAccountIndex, - OwnerAccountIndex: newNft.OwnerAccountIndex, - NftContentHash: newNft.NftContentHash, - NftL1Address: newNft.NftL1Address, - NftL1TokenId: newNft.NftL1TokenId, - CreatorTreasuryRate: newNft.CreatorTreasuryRate, - CollectionId: newNft.CollectionId, - L2BlockHeight: blockHeight, - }) - } - - return pendingNewNft, pendingUpdateNft, pendingNewNftHistory, nil + return pendingNft, pendingNftHistory, nil } func (s *StateDB) DeepCopyAccounts(accountIds []int64) (map[int64]*types.AccountInfo, error) { @@ -637,16 +633,12 @@ func (s *StateDB) GetNextAccountIndex() int64 { } func (s *StateDB) GetNextNftIndex() int64 { - if len(s.PendingNewNftMap) == 0 { - maxNftIndex, err := s.chainDb.L2NftModel.GetLatestNftIndex() - if err != nil { - panic("get latest nft index error: " + err.Error()) - } - return maxNftIndex + 1 + maxNftIndex, err := s.chainDb.L2NftModel.GetLatestNftIndex() + if err != nil { + panic("get latest nft index error: " + err.Error()) } - maxNftIndex := int64(-1) - for index := range s.PendingNewNftMap { + for index := range s.PendingNftMap { if index > maxNftIndex { maxNftIndex = index } diff --git a/dao/account/account.go b/dao/account/account.go index d9f5c4a76..ec820e958 100644 --- a/dao/account/account.go +++ b/dao/account/account.go @@ -43,7 +43,6 @@ type ( GetAccountByNameHash(nameHash string) (account *Account, err error) GetAccounts(limit int, offset int64) (accounts []*Account, err error) GetAccountsTotalCount() (count int64, err error) - CreateAccountsInTransact(tx *gorm.DB, accounts []*Account) error UpdateAccountsInTransact(tx *gorm.DB, accounts []*Account) error } @@ -161,17 +160,6 @@ func (m *defaultAccountModel) GetConfirmedAccountByIndex(accountIndex int64) (ac return account, nil } -func (m *defaultAccountModel) CreateAccountsInTransact(tx *gorm.DB, accounts []*Account) error { - dbTx := tx.Table(m.table).CreateInBatches(accounts, len(accounts)) - if dbTx.Error != nil { - return dbTx.Error - } - if dbTx.RowsAffected != int64(len(accounts)) { - return types.DbErrFailToCreateAccount - } - return nil -} - func (m *defaultAccountModel) UpdateAccountsInTransact(tx *gorm.DB, accounts []*Account) error { for _, account := range accounts { dbTx := tx.Table(m.table).Where("account_index = ?", account.AccountIndex). diff --git a/dao/block/block.go b/dao/block/block.go index 4b1cb5f34..6604b2724 100644 --- a/dao/block/block.go +++ b/dao/block/block.go @@ -89,12 +89,10 @@ type ( Block *Block CompressedBlock *compressedblock.CompressedBlock - PendingNewAccount []*account.Account - PendingUpdateAccount []*account.Account - PendingNewAccountHistory []*account.AccountHistory - PendingNewNft []*nft.L2Nft - PendingUpdateNft []*nft.L2Nft - PendingNewNftHistory []*nft.L2NftHistory + PendingAccount []*account.Account + PendingAccountHistory []*account.AccountHistory + PendingNft []*nft.L2Nft + PendingNftHistory []*nft.L2NftHistory } ) diff --git a/dao/nft/nft.go b/dao/nft/nft.go index dd95ba9c4..feb968c58 100644 --- a/dao/nft/nft.go +++ b/dao/nft/nft.go @@ -35,7 +35,6 @@ type ( GetLatestNftIndex() (nftIndex int64, err error) GetNftsByAccountIndex(accountIndex, limit, offset int64) (nfts []*L2Nft, err error) GetNftsCountByAccountIndex(accountIndex int64) (int64, error) - CreateNftsInTransact(tx *gorm.DB, nfts []*L2Nft) error UpdateNftsInTransact(tx *gorm.DB, nfts []*L2Nft) error } defaultL2NftModel struct { @@ -118,17 +117,6 @@ func (m *defaultL2NftModel) GetNftsCountByAccountIndex(accountIndex int64) (int6 return count, nil } -func (m *defaultL2NftModel) CreateNftsInTransact(tx *gorm.DB, nfts []*L2Nft) error { - dbTx := tx.Table(m.table).CreateInBatches(nfts, len(nfts)) - if dbTx.Error != nil { - return dbTx.Error - } - if dbTx.RowsAffected != int64(len(nfts)) { - return types.DbErrFailToCreateNft - } - return nil -} - func (m *defaultL2NftModel) UpdateNftsInTransact(tx *gorm.DB, nfts []*L2Nft) error { for _, pendingNft := range nfts { dbTx := tx.Table(m.table).Where("nft_index = ?", pendingNft.NftIndex). diff --git a/service/committer/committer/committer.go b/service/committer/committer/committer.go index ebc0ad6fe..387bd9ad9 100644 --- a/service/committer/committer/committer.go +++ b/service/committer/committer/committer.go @@ -274,44 +274,30 @@ func (c *Committer) commitNewBlock(curBlock *block.Block) (*block.Block, error) return err } } - // create new account - if len(blockStates.PendingNewAccount) != 0 { - err = c.bc.DB().AccountModel.CreateAccountsInTransact(tx, blockStates.PendingNewAccount) + // create or update account + if len(blockStates.PendingAccount) != 0 { + err = c.bc.DB().AccountModel.UpdateAccountsInTransact(tx, blockStates.PendingAccount) if err != nil { return err } } - // update account - if len(blockStates.PendingUpdateAccount) != 0 { - err = c.bc.DB().AccountModel.UpdateAccountsInTransact(tx, blockStates.PendingUpdateAccount) + // create account history + if len(blockStates.PendingAccountHistory) != 0 { + err = c.bc.DB().AccountHistoryModel.CreateAccountHistoriesInTransact(tx, blockStates.PendingAccountHistory) if err != nil { return err } } - // create new account history - if len(blockStates.PendingNewAccountHistory) != 0 { - err = c.bc.DB().AccountHistoryModel.CreateAccountHistoriesInTransact(tx, blockStates.PendingNewAccountHistory) + // create or update nft + if len(blockStates.PendingNft) != 0 { + err = c.bc.DB().L2NftModel.UpdateNftsInTransact(tx, blockStates.PendingNft) if err != nil { return err } } - // create new nft - if len(blockStates.PendingNewNft) != 0 { - err = c.bc.DB().L2NftModel.CreateNftsInTransact(tx, blockStates.PendingNewNft) - if err != nil { - return err - } - } - // update nft - if len(blockStates.PendingUpdateNft) != 0 { - err = c.bc.DB().L2NftModel.UpdateNftsInTransact(tx, blockStates.PendingUpdateNft) - if err != nil { - return err - } - } - // new nft history - if len(blockStates.PendingNewNftHistory) != 0 { - err = c.bc.DB().L2NftHistoryModel.CreateNftHistoriesInTransact(tx, blockStates.PendingNewNftHistory) + // create nft history + if len(blockStates.PendingNftHistory) != 0 { + err = c.bc.DB().L2NftHistoryModel.CreateNftHistoriesInTransact(tx, blockStates.PendingNftHistory) if err != nil { return err } From 81f9eac7c5f6b9cdfa68817d55fd75d247428666 Mon Sep 17 00:00:00 2001 From: bnb-twu <114004688+bnb-twu@users.noreply.github.com> Date: Wed, 12 Oct 2022 06:22:19 -0400 Subject: [PATCH 21/23] add golangci-lint install to Makefile (#216) --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index c2681ead6..572c7676a 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ tools: build: api-server build-only lint: + go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.0 golangci-lint run ./... build-only: From 8a0cd45f5465921f098398f0354526462e6df7e2 Mon Sep 17 00:00:00 2001 From: lightning-li Date: Wed, 12 Oct 2022 21:56:50 +0800 Subject: [PATCH 22/23] sender: fix corner case in case the rollup tx is timeout (#221) --- dao/l1rolluptx/l1_rollup_tx.go | 11 +++ service/monitor/monitor/monitor.go | 3 + .../monitor/monitor/monitor_generic_blocks.go | 75 +++++++++++++++++++ service/sender/sender/sender.go | 18 ++++- 4 files changed, 103 insertions(+), 4 deletions(-) diff --git a/dao/l1rolluptx/l1_rollup_tx.go b/dao/l1rolluptx/l1_rollup_tx.go index ee5cc5620..14c277e79 100644 --- a/dao/l1rolluptx/l1_rollup_tx.go +++ b/dao/l1rolluptx/l1_rollup_tx.go @@ -43,6 +43,7 @@ type ( GetLatestHandledTx(txType int64) (tx *L1RollupTx, err error) GetLatestPendingTx(txType int64) (tx *L1RollupTx, err error) GetL1RollupTxsByStatus(txStatus int) (txs []*L1RollupTx, err error) + GetL1RollupTxsByHash(hash string) (txs []*L1RollupTx, err error) DeleteL1RollupTx(tx *L1RollupTx) error UpdateL1RollupTxsInTransact(tx *gorm.DB, txs []*L1RollupTx) error } @@ -104,6 +105,16 @@ func (m *defaultL1RollupTxModel) GetL1RollupTxsByStatus(txStatus int) (txs []*L1 return txs, nil } +func (m *defaultL1RollupTxModel) GetL1RollupTxsByHash(hash string) (txs []*L1RollupTx, err error) { + dbTx := m.DB.Table(m.table).Where("l1_tx_hash = ?", hash).Find(&txs) + if dbTx.Error != nil { + return nil, types.DbErrSqlOperation + } else if dbTx.RowsAffected == 0 { + return nil, types.DbErrNotFound + } + return txs, nil +} + func (m *defaultL1RollupTxModel) DeleteL1RollupTx(rollupTx *L1RollupTx) error { return m.DB.Transaction(func(tx *gorm.DB) error { dbTx := tx.Table(m.table).Where("id = ?", rollupTx.ID).Delete(&rollupTx) diff --git a/service/monitor/monitor/monitor.go b/service/monitor/monitor/monitor.go index 840889a9d..08f21ecff 100644 --- a/service/monitor/monitor/monitor.go +++ b/service/monitor/monitor/monitor.go @@ -31,6 +31,7 @@ import ( "github.com/bnb-chain/zkbnb/dao/l1rolluptx" "github.com/bnb-chain/zkbnb/dao/l1syncedblock" "github.com/bnb-chain/zkbnb/dao/priorityrequest" + "github.com/bnb-chain/zkbnb/dao/proof" "github.com/bnb-chain/zkbnb/dao/sysconfig" "github.com/bnb-chain/zkbnb/dao/tx" "github.com/bnb-chain/zkbnb/service/monitor/config" @@ -65,6 +66,7 @@ type Monitor struct { TxPoolModel tx.TxPoolModel SysConfigModel sysconfig.SysConfigModel L1RollupTxModel l1rolluptx.L1RollupTxModel + ProofModel proof.ProofModel L2AssetModel asset.AssetModel PriorityRequestModel priorityrequest.PriorityRequestModel L1SyncedBlockModel l1syncedblock.L1SyncedBlockModel @@ -83,6 +85,7 @@ func NewMonitor(c config.Config) *Monitor { TxPoolModel: tx.NewTxPoolModel(db), BlockModel: block.NewBlockModel(db), L1RollupTxModel: l1rolluptx.NewL1RollupTxModel(db), + ProofModel: proof.NewProofModel(db), L1SyncedBlockModel: l1syncedblock.NewL1SyncedBlockModel(db), L2AssetModel: asset.NewAssetModel(db), SysConfigModel: sysconfig.NewSysConfigModel(db), diff --git a/service/monitor/monitor/monitor_generic_blocks.go b/service/monitor/monitor/monitor_generic_blocks.go index 81999bdc2..1a2d0eac0 100644 --- a/service/monitor/monitor/monitor_generic_blocks.go +++ b/service/monitor/monitor/monitor_generic_blocks.go @@ -32,9 +32,12 @@ import ( zkbnb "github.com/bnb-chain/zkbnb-eth-rpc/core" "github.com/bnb-chain/zkbnb-eth-rpc/rpc" "github.com/bnb-chain/zkbnb/dao/block" + "github.com/bnb-chain/zkbnb/dao/l1rolluptx" "github.com/bnb-chain/zkbnb/dao/l1syncedblock" "github.com/bnb-chain/zkbnb/dao/priorityrequest" + "github.com/bnb-chain/zkbnb/dao/proof" "github.com/bnb-chain/zkbnb/dao/tx" + types2 "github.com/bnb-chain/zkbnb/types" ) func (m *Monitor) MonitorGenericBlocks() (err error) { @@ -153,8 +156,30 @@ func (m *Monitor) MonitorGenericBlocks() (err error) { // get pending update blocks pendingUpdateBlocks := make([]*block.Block, 0, len(relatedBlocks)) + pendingUpdateCommittedBlocks := make(map[string]*block.Block, 0) + pendingUpdateVerifiedBlocks := make(map[string]*block.Block, 0) for _, pendingUpdateBlock := range relatedBlocks { pendingUpdateBlocks = append(pendingUpdateBlocks, pendingUpdateBlock) + if pendingUpdateBlock.CommittedTxHash != "" { + b, exist := pendingUpdateCommittedBlocks[pendingUpdateBlock.CommittedTxHash] + if exist { + if b.BlockHeight < pendingUpdateBlock.BlockHeight { + pendingUpdateCommittedBlocks[pendingUpdateBlock.CommittedTxHash] = pendingUpdateBlock + } + } else { + pendingUpdateCommittedBlocks[pendingUpdateBlock.CommittedTxHash] = pendingUpdateBlock + } + } + if pendingUpdateBlock.VerifiedTxHash != "" { + b, exist := pendingUpdateVerifiedBlocks[pendingUpdateBlock.VerifiedTxHash] + if exist { + if b.BlockHeight < pendingUpdateBlock.BlockHeight { + pendingUpdateVerifiedBlocks[pendingUpdateBlock.VerifiedTxHash] = pendingUpdateBlock + } + } else { + pendingUpdateVerifiedBlocks[pendingUpdateBlock.VerifiedTxHash] = pendingUpdateBlock + } + } } //update db @@ -174,6 +199,56 @@ func (m *Monitor) MonitorGenericBlocks() (err error) { if err != nil { return err } + // update l1 rollup tx status + // maybe already updated by sender, or may be deleted by sender because of timeout + for _, val := range pendingUpdateCommittedBlocks { + _, err = m.L1RollupTxModel.GetL1RollupTxsByHash(val.CommittedTxHash) + if err == types2.DbErrNotFound { + logx.Info("monitor create commit rollup tx ", val.CommittedTxHash, val.BlockHeight) + // the rollup tx is deleted by sender + // so we insert it here + err = m.L1RollupTxModel.CreateL1RollupTx(&l1rolluptx.L1RollupTx{ + L1TxHash: val.CommittedTxHash, + TxStatus: l1rolluptx.StatusHandled, + TxType: l1rolluptx.TxTypeCommit, + L2BlockHeight: val.BlockHeight, + }) + if err != nil { + return err + } + } else if err != nil { + return err + } + } + pendingUpdateProofStatus := make(map[int64]int) + for _, val := range pendingUpdateVerifiedBlocks { + _, err = m.L1RollupTxModel.GetL1RollupTxsByHash(val.VerifiedTxHash) + if err == types2.DbErrNotFound { + logx.Info("monitor create verify rollup tx ", val.VerifiedTxHash, val.BlockHeight) + // the rollup tx is deleted by sender + // so we insert it here + err = m.L1RollupTxModel.CreateL1RollupTx(&l1rolluptx.L1RollupTx{ + L1TxHash: val.VerifiedTxHash, + TxStatus: l1rolluptx.StatusHandled, + TxType: l1rolluptx.TxTypeVerifyAndExecute, + L2BlockHeight: val.BlockHeight, + }) + if err != nil { + return err + } + } else if err != nil { + return err + } + pendingUpdateProofStatus[val.BlockHeight] = proof.Confirmed + } + // update proof status + if len(pendingUpdateProofStatus) != 0 { + err = m.ProofModel.UpdateProofsInTransact(tx, pendingUpdateProofStatus) + if err != nil { + return err + } + } + //update tx status err = m.TxModel.UpdateTxsStatusInTransact(tx, relatedBlockTxStatus) return err diff --git a/service/sender/sender/sender.go b/service/sender/sender/sender.go index 0907c507b..dd76bb42e 100644 --- a/service/sender/sender/sender.go +++ b/service/sender/sender/sender.go @@ -172,7 +172,7 @@ func (s *Sender) CommitBlocks() (err error) { gasPrice, s.config.ChainConfig.GasLimit) if err != nil { - return fmt.Errorf("failed to send commit tx, errL %v", err) + return fmt.Errorf("failed to send commit tx, errL %v:%s", err, txHash) } newRollupTx := &l1rolluptx.L1RollupTx{ L1TxHash: txHash, @@ -184,7 +184,7 @@ func (s *Sender) CommitBlocks() (err error) { if err != nil { return fmt.Errorf("failed to create tx in database, err: %v", err) } - logx.Infof("new blocks have been committed(height): %v", newRollupTx.L2BlockHeight) + logx.Infof("new blocks have been committed(height): %v:%s", newRollupTx.L2BlockHeight, newRollupTx.L1TxHash) return nil } @@ -220,6 +220,10 @@ func (s *Sender) UpdateSentTxs() (err error) { continue } if receipt.Status == 0 { + // Should direct mark tx deleted + logx.Infof("delete timeout l1 rollup tx, tx_hash=%s", pendingTx.L1TxHash) + //nolint:errcheck + s.l1RollupTxModel.DeleteL1RollupTx(pendingTx) // It is critical to have any failed transactions panic(fmt.Sprintf("unexpected failed tx: %v", txHash)) } @@ -317,6 +321,12 @@ func (s *Sender) VerifyAndExecuteBlocks() (err error) { if len(blockProofs) != len(blocks) { return errors.New("related proofs not ready") } + // add sanity check + for i := range blockProofs { + if blockProofs[i].BlockNumber != blocks[i].BlockHeight { + return errors.New("proof number not match") + } + } var proofs []*big.Int for _, bProof := range blockProofs { var proofInfo *prove.FormattedProof @@ -345,7 +355,7 @@ func (s *Sender) VerifyAndExecuteBlocks() (err error) { txHash, err := zkbnb.VerifyAndExecuteBlocks(cli, authCli, zkbnbInstance, pendingVerifyAndExecuteBlocks, proofs, gasPrice, s.config.ChainConfig.GasLimit) if err != nil { - return fmt.Errorf("failed to send verify tx: %v", err) + return fmt.Errorf("failed to send verify tx: %v:%s", err, txHash) } newRollupTx := &l1rolluptx.L1RollupTx{ @@ -358,7 +368,7 @@ func (s *Sender) VerifyAndExecuteBlocks() (err error) { if err != nil { return fmt.Errorf(fmt.Sprintf("failed to create rollup tx in db %v", err)) } - logx.Infof("new blocks have been verified and executed(height): %d", newRollupTx.L2BlockHeight) + logx.Infof("new blocks have been verified and executed(height): %d:%s", newRollupTx.L2BlockHeight, newRollupTx.L1TxHash) return nil } From d23d52d7677c22be0e63d657769e9573ca37f8f3 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Thu, 13 Oct 2022 12:09:02 +0800 Subject: [PATCH 23/23] dep: bump the version of zkbnb-crypto to v0.0.7 --- go.mod | 2 +- go.sum | 4 ++-- service/apiserver/server.api | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 78dca50e4..a199bc164 100644 --- a/go.mod +++ b/go.mod @@ -90,7 +90,7 @@ require ( ) require ( - github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221012064947-a395ff5a2614 + github.com/bnb-chain/zkbnb-crypto v0.0.7 github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f github.com/consensys/gnark v0.7.0 diff --git a/go.sum b/go.sum index ad3f85230..b1f536444 100644 --- a/go.sum +++ b/go.sum @@ -117,8 +117,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221012064947-a395ff5a2614 h1:a+POfow+uc60upenBUrzo9XW/nk7H9llv45UVdF67xw= -github.com/bnb-chain/zkbnb-crypto v0.0.6-0.20221012064947-a395ff5a2614/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= +github.com/bnb-chain/zkbnb-crypto v0.0.7 h1:IckShzkNdx/ee461Gd0kMC04phus8fcRdIeuzSz1PDE= +github.com/bnb-chain/zkbnb-crypto v0.0.7/go.mod h1:L1BEYSG945hwjJCtR5LUQ1pvRmydSsk9oU2d9YvoOrA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2 h1:1rMa8XpplDNZaxeM1ifXMjSSeH/ucJyLUjHHEw1z4AA= github.com/bnb-chain/zkbnb-eth-rpc v0.0.2/go.mod h1:T69T8enicQ5kSRPIzyPJv/jhuvRMz1UxsijPXmlis+I= github.com/bnb-chain/zkbnb-smt v0.0.2-0.20220919093003-13980385d38f h1:zBVWOWlH4w18O6wp0gZML4U2n1rxsFLb7KB7DFE8zcQ= diff --git a/service/apiserver/server.api b/service/apiserver/server.api index f387d8bde..0c982d982 100644 --- a/service/apiserver/server.api +++ b/service/apiserver/server.api @@ -41,13 +41,13 @@ type ( } Account { - Status uint32 `json:"status"` - Index int64 `json:"index"` - Name string `json:"name"` - Pk string `json:"pk"` - Nonce int64 `json:"nonce"` - Assets []*AccountAsset `json:"assets"` - TotalAssetValue string `json:"total_asset_value"` + Status uint32 `json:"status"` + Index int64 `json:"index"` + Name string `json:"name"` + Pk string `json:"pk"` + Nonce int64 `json:"nonce"` + Assets []*AccountAsset `json:"assets"` + TotalAssetValue string `json:"total_asset_value"` } SimpleAccount {