diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..5a1bbfe6f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,60 @@ +name: Publish +on: + push: + tags: + - '*' +jobs: + publish: + name: Publish for ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + asset_name: linux_amd64 + - os: macos-latest + asset_name: darwin_amd64 + steps: + + - name: Set up Go 1.16 + uses: actions/setup-go@v2 + with: + go-version: ^1.16 + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - name: Set version to environment variables + id: get-version + run: | + rm -rf build + mkdir -p assets + echo ::set-output name=GIT_COMMIT::$(git rev-parse --short=8 HEAD) + echo ::set-output name=VERSION::$(awk -F\" '/Version =/ { print $2; exit }' < version/version.go) + + - name: Building version ${{ steps.get-version.outputs.VERSION }} for ${{ matrix.asset_name }} + run: | + make build_c + + - name: Packaging in zip archive + run: | + zip -j "./assets/minter_${{ steps.get-version.outputs.VERSION }}_${{ steps.get-version.outputs.GIT_COMMIT }}_${{ matrix.asset_name }}.zip" ./build/minter + shasum -a256 ./assets/minter_${{ steps.get-version.outputs.VERSION }}_${{ steps.get-version.outputs.GIT_COMMIT }}_${{ matrix.asset_name }}.zip > "./assets/minter_${{ steps.get-version.outputs.VERSION }}_${{ steps.get-version.outputs.GIT_COMMIT }}_${{ matrix.asset_name }}_SHA256SUMS" + + - name: Upload binary to release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ./assets/minter_${{ steps.get-version.outputs.VERSION }}_${{ steps.get-version.outputs.GIT_COMMIT }}_${{ matrix.asset_name }}.zip + tag: ${{ github.ref }} + file_glob: true + overwrite: true + + - name: Upload SHA256SUMS to release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ./assets/minter_${{ steps.get-version.outputs.VERSION }}_${{ steps.get-version.outputs.GIT_COMMIT }}_${{ matrix.asset_name }}_SHA256SUMS + tag: ${{ github.ref }} + file_glob: true + overwrite: true \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ac9a8321..213cb8d9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,26 @@ # Changelog +## [v2.5.0](https://github.com/MinterTeam/minter-go-node/tree/v2.5.0) + +[Full Changelog](https://github.com/MinterTeam/minter-go-node/compare/v2.4.1...v2.5.0) + +### Added + +- Commission fee for unsuccessful transactions +- Prioritizing transactions in a block based on gas multiplier (not enabled) + +### Fixed + +- Custom commissions with gas multiplier +- Parallel getting and updating of balances + ## [v2.4.1](https://github.com/MinterTeam/minter-go-node/tree/v2.4.1) [Full Changelog](https://github.com/MinterTeam/minter-go-node/compare/v2.4.0...v2.4.1) ### Fixed -- Fixed deadlock in block's commit +- Deadlock in block's commit - Backward compatibility of older blocks ## [v2.4.0](https://github.com/MinterTeam/minter-go-node/tree/v2.4.0) @@ -40,7 +54,7 @@ ### Fixed -- Fix a critical bug in the exchange transaction through the pool +- Critical bug in the exchange transaction through the pool - Import and export for new entities - Graceful stop of the node @@ -58,7 +72,7 @@ ### Fixed -- Fix issue with db corruption while using delegated balance of addresses API +- Issue with db corruption while using delegated balance of addresses API - Improved processing of incoming transactions ## [v2.0.2](https://github.com/MinterTeam/minter-go-node/tree/v2.0.2) @@ -75,7 +89,7 @@ ### Fixed -- Fix issue with db corruption while using list of candidates API +- Issue with db corruption while using list of candidates API - Connecting to peers with cli ### Added diff --git a/Makefile b/Makefile index e7cc4318a..2ea775b16 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ build: CGO_ENABLED=0 go build $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' -o build/minter ./cmd/minter/ build_c: - CGO_ENABLED=1 go build $(BUILD_FLAGS) -tags '$(BUILD_TAGS) gcc cleveldb' -o build/minter ./cmd/minter/ + CGO_ENABLED=1 go build $(BUILD_FLAGS) -tags '$(BUILD_TAGS) gcc' -o build/minter ./cmd/minter/ install: CGO_ENABLED=0 go install $(BUILD_FLAGS) -tags '$(BUILD_TAGS)' ./cmd/minter diff --git a/api/v2/service/address.go b/api/v2/service/address.go index ff4934a43..5e70fb8e5 100644 --- a/api/v2/service/address.go +++ b/api/v2/service/address.go @@ -4,15 +4,17 @@ import ( "context" "encoding/hex" "fmt" + "math/big" + "strings" + "github.com/MinterTeam/minter-go-node/coreV2/state" + "github.com/MinterTeam/minter-go-node/coreV2/state/accounts" "github.com/MinterTeam/minter-go-node/coreV2/state/coins" "github.com/MinterTeam/minter-go-node/coreV2/types" "github.com/MinterTeam/minter-go-node/formula" pb "github.com/MinterTeam/node-grpc-gateway/api_pb" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "math/big" - "strings" ) type stakeUser struct { @@ -144,9 +146,33 @@ func (s *Service) Address(ctx context.Context, req *pb.AddressRequest) (*pb.Addr } res.BipValue = coinsBipValue.String() res.TransactionCount = cState.Accounts().GetNonce(address) + + res.Multisig = s.getMultisig(cState.Accounts().GetAccount(address)) + return &res, nil } +func (s *Service) getMultisig(account *accounts.Model) *pb.Multisig { + if !account.IsMultisig() { + return nil + } + + multisig := account.Multisig() + var weights []uint64 + for _, weight := range multisig.Weights { + weights = append(weights, uint64(weight)) + } + var addresses []string + for _, add := range multisig.Addresses { + addresses = append(addresses, add.String()) + } + return &pb.Multisig{ + Threshold: uint64(multisig.Threshold), + Weights: weights, + Addresses: addresses, + } +} + func customCoinBipBalance(valueToSell *big.Int, coinFrom *coins.Model) *big.Int { if coinFrom.ID().IsBaseCoin() { return valueToSell diff --git a/api/v2/service/addresses.go b/api/v2/service/addresses.go index 485373b46..26821d028 100644 --- a/api/v2/service/addresses.go +++ b/api/v2/service/addresses.go @@ -4,12 +4,13 @@ import ( "context" "encoding/hex" "fmt" + "math/big" + "strings" + "github.com/MinterTeam/minter-go-node/coreV2/types" pb "github.com/MinterTeam/node-grpc-gateway/api_pb" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "math/big" - "strings" ) // Addresses returns list of addresses. @@ -139,7 +140,7 @@ func (s *Service) Addresses(ctx context.Context, req *pb.AddressesRequest) (*pb. } res.BipValue = coinsBipValue.String() res.TransactionCount = cState.Accounts().GetNonce(address) - + res.Multisig = s.getMultisig(cState.Accounts().GetAccount(address)) response.Addresses[addr] = &res } diff --git a/api/v2/service/data_encoder.go b/api/v2/service/data_encoder.go index 0d96c13b9..ab3974fbf 100644 --- a/api/v2/service/data_encoder.go +++ b/api/v2/service/data_encoder.go @@ -323,7 +323,7 @@ func encode(data transaction.Data, txType transaction.TxType, rCoins coins.RCoin Commission: uint64(d.Commission), } case transaction.TypeVoteCommission: - d := data.(*transaction.VoteCommissionDataV1) + d := data.(*transaction.VoteCommissionDataV250) m = priceCommissionData(d, rCoins.GetCoin(d.Coin)) case transaction.TypeVoteUpdate: d := data.(*transaction.VoteUpdateDataV230) @@ -358,7 +358,7 @@ func encode(data transaction.Data, txType transaction.TxType, rCoins coins.RCoin return a, nil } -func priceCommissionData(d *transaction.VoteCommissionDataV1, coin *coins.Model) proto.Message { +func priceCommissionData(d *transaction.VoteCommissionDataV250, coin *coins.Model) proto.Message { return &pb.VoteCommissionData{ PubKey: d.PubKey.String(), Height: d.Height, @@ -408,7 +408,9 @@ func priceCommissionData(d *transaction.VoteCommissionDataV1, coin *coins.Model) BurnToken: d.BurnToken.String(), VoteCommission: d.VoteCommission.String(), VoteUpdate: d.VoteUpdate.String(), - // FailedTx: d.FailedTX.String(), + FailedTx: d.FailedTxPrice().String(), + AddLimitOrder: d.AddLimitOrderPrice().String(), + RemoveLimitOrder: d.RemoveLimitOrderPrice().String(), } } diff --git a/api/v2/service/estimate_coin_buy.go b/api/v2/service/estimate_coin_buy.go index 68dff6a01..d2a5600b2 100644 --- a/api/v2/service/estimate_coin_buy.go +++ b/api/v2/service/estimate_coin_buy.go @@ -168,7 +168,7 @@ func (s *Service) calcBuyFromPool(ctx context.Context, value *big.Int, cState *s swapChecker := cState.Swap().GetSwapper(sellCoinID, buyCoinID) if !swapChecker.Exists() { - return nil, s.createError(status.New(codes.NotFound, fmt.Sprintf("swap pool beetwen coins %s and %s not exists", coinFrom.GetFullSymbol(), coinBuy.GetFullSymbol())), transaction.EncodeError(code.NewPairNotExists(coinFrom.ID().String(), coinBuy.ID().String()))) + return nil, s.createError(status.New(codes.NotFound, fmt.Sprintf("swap pool between coins %s and %s not exists", coinFrom.GetFullSymbol(), coinBuy.GetFullSymbol())), transaction.EncodeError(code.NewPairNotExists(coinFrom.ID().String(), coinBuy.ID().String()))) } if _, ok := dup[swapChecker.GetID()]; ok { @@ -188,7 +188,7 @@ func (s *Service) calcBuyFromPool(ctx context.Context, value *big.Int, cState *s if sellValue == nil { reserve0, reserve1 := swapChecker.Reserves() symbolOut := coinBuy.GetFullSymbol() - return nil, s.createError(status.New(codes.FailedPrecondition, fmt.Sprintf("You wanted to buy %s %s, but pool reserve has only %s %s", value, symbolOut, reserve1.String(), symbolOut)), transaction.EncodeError(code.NewInsufficientLiquidity(coinFrom.ID().String(), sellValue.String(), coinBuy.ID().String(), value.String(), reserve0.String(), reserve1.String()))) + return nil, s.createError(status.New(codes.FailedPrecondition, fmt.Sprintf("You wanted to buy %s %s, but pool reserve has only %s %s", value, symbolOut, reserve1.String(), symbolOut)), transaction.EncodeError(code.NewInsufficientLiquidity(coinFrom.ID().String(), "", coinBuy.ID().String(), value.String(), reserve0.String(), reserve1.String()))) } coinSell := coinFrom @@ -229,8 +229,9 @@ func (s *Service) calcBuyFromBancor(value *big.Int, coinTo transaction.Calculate value = formula.CalculatePurchaseAmount(coinTo.Volume(), coinTo.Reserve(), coinTo.Crr(), value) } if !coinFrom.ID().IsBaseCoin() { - value = formula.CalculateSaleAmount(coinFrom.Volume(), coinFrom.Reserve(), coinFrom.Crr(), value) - if errResp := transaction.CheckReserveUnderflow(coinFrom, value); errResp != nil { + var errResp *transaction.Response + value, errResp = transaction.CalculateSaleAmountAndCheck(coinFrom, value) + if errResp != nil { return nil, s.createError(status.New(codes.FailedPrecondition, errResp.Log), errResp.Info) } } diff --git a/api/v2/service/estimate_coin_sell.go b/api/v2/service/estimate_coin_sell.go index dcb3f6cec..34c9b389f 100644 --- a/api/v2/service/estimate_coin_sell.go +++ b/api/v2/service/estimate_coin_sell.go @@ -308,8 +308,9 @@ func (s *Service) calcSellFromBancor(value *big.Int, coinTo transaction.Calculat } if !coinFrom.ID().IsBaseCoin() { - value = formula.CalculateSaleReturn(coinFrom.Volume(), coinFrom.Reserve(), coinFrom.Crr(), value) - if errResp := transaction.CheckReserveUnderflow(coinFrom, value); errResp != nil { + var errResp *transaction.Response + value, errResp = transaction.CalculateSaleReturnAndCheck(coinFrom, value) + if errResp != nil { return nil, s.createError(status.New(codes.FailedPrecondition, errResp.Log), errResp.Info) } } diff --git a/api/v2/service/price_commission.go b/api/v2/service/price_commission.go index 7c1203660..59247ff70 100644 --- a/api/v2/service/price_commission.go +++ b/api/v2/service/price_commission.go @@ -40,10 +40,10 @@ func priceCommissionResponse(price *commission.Price, coin *coins.Model) *pb.Pri SellBancor: price.SellBancor.String(), SellAllBancor: price.SellAllBancor.String(), BuyPoolBase: price.BuyPoolBase.String(), - SellPoolBase: price.SellPoolBase.String(), - SellAllPoolBase: price.SellAllPoolBase.String(), BuyPoolDelta: price.BuyPoolDelta.String(), + SellPoolBase: price.SellPoolBase.String(), SellPoolDelta: price.SellPoolDelta.String(), + SellAllPoolBase: price.SellAllPoolBase.String(), SellAllPoolDelta: price.SellAllPoolDelta.String(), CreateTicker3: price.CreateTicker3.String(), CreateTicker4: price.CreateTicker4.String(), @@ -77,5 +77,7 @@ func priceCommissionResponse(price *commission.Price, coin *coins.Model) *pb.Pri VoteCommission: price.VoteCommission.String(), VoteUpdate: price.VoteUpdate.String(), FailedTx: price.FailedTxPrice().String(), + AddLimitOrder: price.AddLimitOrderPrice().String(), + RemoveLimitOrder: price.RemoveLimitOrderPrice().String(), } } diff --git a/api/v2/v2.go b/api/v2/v2.go index 11495f269..65a0514c3 100644 --- a/api/v2/v2.go +++ b/api/v2/v2.go @@ -153,7 +153,8 @@ func serveOpenAPI(prefix string, mux *http.ServeMux) error { func unaryTimeoutInterceptor(timeout time.Duration) func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - withTimeout, _ := context.WithTimeout(ctx, timeout) + withTimeout, cancel := context.WithTimeout(ctx, timeout) + defer cancel() return handler(withTimeout, req) } } diff --git a/cmd/minter/cmd/node.go b/cmd/minter/cmd/node.go index 8806eb06f..8e4c0bbeb 100644 --- a/cmd/minter/cmd/node.go +++ b/cmd/minter/cmd/node.go @@ -184,106 +184,13 @@ func checkRlimits() error { } func startTendermintNode(app *minter.Blockchain, cfg *tmCfg.Config, logger tmLog.Logger, home string) *tmNode.Node { - // stateDB, err := tmNode.DefaultDBProvider(&tmNode.DBContext{ID: "state", Config: cfg}) // each state needs its own db - // if err != nil { - // panic(err) - // } - // blockDB, err := tmNode.DefaultDBProvider(&tmNode.DBContext{ID: "blockstore", Config: cfg}) - // if err != nil { - // panic(err) - // } - // evidenceDB, err := tmNode.DefaultDBProvider(&tmNode.DBContext{ID: "evidence", Config: cfg}) - // if err != nil { - // panic(err) - // } - // defaultDBProvider := func(ctx *tmNode.DBContext) (dbm.DB, error) { - // switch ctx.ID { - // case "state": - // if stateDB == nil { - // break - // } - // return stateDB, nil - // case "blockstore": - // if blockDB == nil { - // break - // } - // return blockDB, nil - // case "evidence": - // if evidenceDB == nil { - // break - // } - // return evidenceDB, nil - // } - // dbType := dbm.BackendType(ctx.Config.DBBackend) - // return dbm.NewDB(ctx.ID, dbType, ctx.Config.DBDir()) - // } nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile()) if err != nil { panic(err) } genesis := getGenesis(home + "/config/genesis.json") - // doc, err := genesis() - // if err != nil { - // panic(err) - // } - - /*csMetrics, p2pMetrics, memplMetrics, smMetrics*/ - // csMetrics, _, _, smMetrics := tmNode.DefaultMetricsProvider(cfg.Instrumentation)(doc.ChainID) - creator := proxy.NewLocalClientCreator(app) - // - // appConnMem, _ := creator.NewABCIClient() - // appConnMem.SetLogger(logger.With("module", "abci-client", "connection", "mempool")) - // - // if err := appConnMem.Start(); err != nil { - // panic(err) - // } - // - // // priorityMempool := mempool.NewPriorityMempool(cfg.Mempool, appConnMem, 0) - // priorityMempool := mempl.NewCListMempool(cfg.Mempool, appConnMem, 0) - // priorityMempool.SetLogger(logger) - // - // mempoolLogger := logger.With("module", "mempool") - // // mempoolReactor := mempool.NewReactor(cfg.Mempool, priorityMempool) - // mempoolReactor := mempl.NewReactor(cfg.Mempool, priorityMempool) - // mempoolReactor.SetLogger(mempoolLogger) - // - // if cfg.Consensus.WaitForTxs() { - // priorityMempool.EnableTxsAvailable() - // } - // - // stateStore := sm.NewStore(stateDB) - // - // blockStore := store.NewBlockStore(blockDB) - // - // // Make a full instance of the evidence pool - // - // evpool, err := evidence.NewPool(evidenceDB, stateStore, blockStore) - // if err != nil { - // panic(err) - // } - // evpool.SetLogger(logger.With("module", "evidence")) - // - // state, _ := stateStore.LoadFromDBOrGenesisDoc(doc) - // // Make State - // blockExec := sm.NewBlockExecutor(stateStore, logger.With("module", "state"), appConnMem, priorityMempool, evpool /*sm.BlockExecutorWithMetrics(smMetrics)*/) - // cs := consensus.NewState(cfg.Consensus, state, blockExec, blockStore, priorityMempool, evpool /*consensus.StateMetrics(csMetrics)*/) - // cs.SetLogger(cs.Logger) - // - // var bcReactor p2p.Reactor - // switch cfg.FastSync.Version { - // case "v0": - // bcReactor = bcv0.NewBlockchainReactor(state.Copy(), blockExec, blockStore, cfg.FastSyncMode) - // case "v1": - // bcReactor = bcv1.NewBlockchainReactor(state.Copy(), blockExec, blockStore, cfg.FastSyncMode) - // case "v2": - // bcReactor = bcv2.NewBlockchainReactor(state.Copy(), blockExec, blockStore, cfg.FastSyncMode) - // default: - // panic(fmt.Sprintf("unknown fastsync version %s", cfg.FastSync.Version)) - // } - // bcReactor = bcv0.NewBlockchainReactor(state.Copy(), blockExec, blockStore, cfg.FastSyncMode) - // bcReactor.SetLogger(logger.With("module", "blockchain")) node, err := tmNode.NewNode( cfg, @@ -293,33 +200,26 @@ func startTendermintNode(app *minter.Blockchain, cfg *tmCfg.Config, logger tmLog genesis, tmNode.DefaultDBProvider, tmNode.DefaultMetricsProvider(cfg.Instrumentation), - // func(config *tmCfg.Config, proxyApp proxy.AppConns, state sm.State, memplMetrics *tmpool.Metrics, logger tmLog.Logger) (*tmpool.Reactor, tmpool.Mempool) { - // mempool := mempl.NewPriorityMempool( - // config.Mempool, - // proxyApp.Mempool(), - // state.LastBlockHeight, - // mempl.WithMetrics(memplMetrics), - // mempl.WithPreCheck(sm.TxPreCheck(state)), - // mempl.WithPostCheck(sm.TxPostCheck(state)), - // ) - // mempoolLogger := logger.With("module", "mempool") - // mempoolReactor := tmpool.NewReactor(config.Mempool, mempool) - // mempoolReactor.SetLogger(mempoolLogger) + //func(config *tmCfg.Config, proxyApp proxy.AppConns, state sm.State, memplMetrics *tmpool.Metrics, logger tmLog.Logger) (*tmpool.Reactor, tmpool.Mempool) { + // mempool := mempl.NewPriorityMempool( + // config.Mempool, + // proxyApp.Mempool(), + // state.LastBlockHeight, + // mempl.WithMetrics(memplMetrics), + // mempl.WithPreCheck(sm.TxPreCheck(state)), + // mempl.WithPostCheck(sm.TxPostCheck(state)), + // ) + // mempoolLogger := logger.With("module", "mempool") + // mempoolReactor := tmpool.NewReactor(config.Mempool, mempool) + // mempoolReactor.SetLogger(mempoolLogger) // - // if config.Consensus.WaitForTxs() { - // mempool.EnableTxsAvailable() - // } + // if config.Consensus.WaitForTxs() { + // mempool.EnableTxsAvailable() + // } // - // return mempoolReactor, mempool - // }, - nil, + // return mempoolReactor, mempool + //}, logger.With("module", "tendermint"), - // tmNode.CustomReactors(map[string]p2p.Reactor{ - // // "MEMPOOL": mempoolReactor, - // "CONSENSUS": consensus.NewReactor(cs, true), - // // "EVIDENCE": evidence.NewReactor(evpool), - // // "BLOCKCHAIN": bcReactor, - // }), ) if err != nil { diff --git a/coreV2/events/types.go b/coreV2/events/types.go index 639d43746..c1e931758 100644 --- a/coreV2/events/types.go +++ b/coreV2/events/types.go @@ -413,6 +413,8 @@ type UpdateCommissionsEvent struct { VoteCommission string `json:"vote_commission"` VoteUpdate string `json:"vote_update"` FailedTx string `json:"failed_tx"` + AddLimitOrder string `json:"add_limit_order"` + RemoveLimitOrder string `json:"remove_limit_order"` } func (ce *UpdateCommissionsEvent) Type() string { diff --git a/coreV2/mempool/bench_test.go b/coreV2/mempool/bench_test.go new file mode 100644 index 000000000..bced28f05 --- /dev/null +++ b/coreV2/mempool/bench_test.go @@ -0,0 +1,42 @@ +package mempool + +import ( + "github.com/tendermint/tendermint/abci/example/kvstore" + tmpool "github.com/tendermint/tendermint/mempool" + "github.com/tendermint/tendermint/proxy" + "testing" +) + +func BenchmarkReap(b *testing.B) { + app := kvstore.NewApplication() + cc := proxy.NewLocalClientCreator(app) + mempool, cleanup := newMempoolWithApp(cc) + defer cleanup() + + size := 10000 + mempool.config.Size = size + for i := 0; i < size; i++ { + tx := createTxWithRandomGas(116, nil) + if err := mempool.CheckTx(tx, nil, tmpool.TxInfo{}); err != nil { + b.Error(err) + } + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + mempool.ReapMaxBytesMaxGas(100000000, 10000000) + } +} + +func BenchmarkCheckTx(b *testing.B) { + app := kvstore.NewApplication() + cc := proxy.NewLocalClientCreator(app) + mempool, cleanup := newMempoolWithApp(cc) + defer cleanup() + + for i := 0; i < b.N; i++ { + tx := createTxWithRandomGas(116, nil) + if err := mempool.CheckTx(tx, nil, tmpool.TxInfo{}); err != nil { + b.Error(err) + } + } +} diff --git a/coreV2/mempool/priority_mempool.go b/coreV2/mempool/priority_mempool.go index b263507d1..8ce0a68b6 100644 --- a/coreV2/mempool/priority_mempool.go +++ b/coreV2/mempool/priority_mempool.go @@ -4,13 +4,12 @@ import ( "bytes" "crypto/sha256" "fmt" + "github.com/MinterTeam/minter-go-node/coreV2/transaction" + tmpool "github.com/tendermint/tendermint/mempool" "sort" "sync" "sync/atomic" - "github.com/MinterTeam/minter-go-node/coreV2/transaction" - tmpool "github.com/tendermint/tendermint/mempool" - abci "github.com/tendermint/tendermint/abci/types" cfg "github.com/tendermint/tendermint/config" auto "github.com/tendermint/tendermint/libs/autofile" @@ -29,26 +28,7 @@ const TxKeySize = sha256.Size var newline = []byte("\n") -// -------------------------------------------------------------------------------- - -// Reactor handles mempool tx broadcasting amongst peers. -// It maintains a map from peer ID to counter, to prevent gossiping txs to the -// peers you received it from. -type Reactor struct { - p2p.BaseReactor - config *cfg.MempoolConfig - mempool *PriorityMempool -} - -// NewReactor returns a new Reactor with the given config and mempool. -func NewReactor(config *cfg.MempoolConfig, mempool *PriorityMempool) *Reactor { - memR := &Reactor{ - config: config, - mempool: mempool, - } - memR.BaseReactor = *p2p.NewBaseReactor("Mempool", memR) - return memR -} +//-------------------------------------------------------------------------------- // PriorityMempool is an ordered in-memory pool for transactions before they are // proposed in a consensus round. Transaction validity is checked using the @@ -72,16 +52,9 @@ type PriorityMempool struct { preCheck tmpool.PreCheckFunc postCheck tmpool.PostCheckFunc - wal *auto.AutoFile // a log of mempool txs - txs map[uint32]*clist.CList // concurrent linked-list of good txs - txsGasPriceCounter map[uint32]uint64 - gasPrices []uint32 - txsCounter int - proxyAppConn proxy.AppConnMempool - - // locks - txsmx sync.RWMutex - txscmx sync.RWMutex + wal *auto.AutoFile // a log of mempool txs + txs *clist.CList // concurrent linked-list of good txs + proxyAppConn proxy.AppConnMempool // Track whether we're rechecking txs. // These are not protected by a mutex and are expected to be mutated in @@ -99,11 +72,17 @@ type PriorityMempool struct { logger log.Logger - metrics *tmpool.Metrics + metrics *tmpool.Metrics + executor transaction.DecoderTx + + txsgpmu sync.RWMutex + txsByGas map[uint32]map[[32]byte]*tmpool.MempoolTx + minterTxMap sync.Map + gasPrices []uint32 } -// PriorityMempoolOption sets an optional parameter on the tmpool. +// PriorityMempoolOption sets an optional parameter on the mempool. type PriorityMempoolOption func(*PriorityMempool) // NewPriorityMempool returns a new mempool with the given configuration and connection to an application. @@ -114,17 +93,16 @@ func NewPriorityMempool( options ...PriorityMempoolOption, ) *PriorityMempool { mempool := &PriorityMempool{ - config: config, - proxyAppConn: proxyAppConn, - txs: make(map[uint32]*clist.CList), - txsGasPriceCounter: make(map[uint32]uint64), - txsCounter: 0, - height: height, - recheckCursor: nil, - recheckEnd: nil, - logger: log.NewNopLogger(), - metrics: tmpool.NopMetrics(), - executor: transaction.NewExecutor(transaction.GetData), + config: config, + proxyAppConn: proxyAppConn, + txs: clist.New(), + height: height, + recheckCursor: nil, + recheckEnd: nil, + logger: log.NewNopLogger(), + metrics: tmpool.NopMetrics(), + executor: transaction.NewExecutor(transaction.GetData), + txsByGas: make(map[uint32]map[[32]byte]*tmpool.MempoolTx), } if config.CacheSize > 0 { mempool.cache = newMapTxCache(config.CacheSize) @@ -206,7 +184,7 @@ func (mem *PriorityMempool) Unlock() { // Safe for concurrent use by multiple goroutines. func (mem *PriorityMempool) Size() int { - return mem.txsCounter + return mem.txs.Len() } // Safe for concurrent use by multiple goroutines. @@ -214,47 +192,6 @@ func (mem *PriorityMempool) TxsBytes() int64 { return atomic.LoadInt64(&mem.txsBytes) } -func (mem *PriorityMempool) txsByGasPrices() ([]uint32, uint64) { - mem.txscmx.RLock() - defer mem.txscmx.RUnlock() - - gasPrices, txCount := make([]uint32, 0), uint64(0) - for gasPrice, count := range mem.txsGasPriceCounter { - if count > 0 { - txCount += count - gasPrices = append(gasPrices, gasPrice) - } - } - - sort.Slice(gasPrices, func(i, j int) bool { return gasPrices[i] > gasPrices[j] }) - return gasPrices, txCount -} - -func (mem *PriorityMempool) incrementTxsCounter(gasPrice uint32) { - mem.txscmx.Lock() - defer mem.txscmx.Unlock() - - mem.txsCounter += 1 - if _, ok := mem.txsGasPriceCounter[gasPrice]; ok { - mem.txsGasPriceCounter[gasPrice] += 1 - return - } - - mem.txsGasPriceCounter[gasPrice] = 1 -} - -func (mem *PriorityMempool) decrementTxsCounter(gasPrice uint32) { - mem.txscmx.Lock() - defer mem.txscmx.Unlock() - - mem.txsCounter -= 1 - mem.txsGasPriceCounter[gasPrice] -= 1 - - if mem.txsGasPriceCounter[gasPrice] == 0 { - mem.removeGasPrice(gasPrice) - } -} - // Lock() must be help by the caller during execution. func (mem *PriorityMempool) FlushAppConn() error { return mem.proxyAppConn.FlushSync() @@ -268,16 +205,10 @@ func (mem *PriorityMempool) Flush() { _ = atomic.SwapInt64(&mem.txsBytes, 0) mem.cache.Reset() - gasPrices, _ := mem.txsByGasPrices() - for _, gp := range gasPrices { - for e := mem.getTxByGasPrice(gp).Front(); e != nil; e = e.Next() { - mem.txsmx.Lock() - mem.txs[gp].Remove(e) - mem.txsmx.Unlock() - - e.DetachPrev() - mem.decrementTxsCounter(gp) - } + for e := mem.txs.Front(); e != nil; e = e.Next() { + mem.txs.Remove(e) + mem.removeTxFromTxsGasPriceMap(e.Value.(*tmpool.MempoolTx).Tx) + e.DetachPrev() } mem.txsMap.Range(func(key, _ interface{}) bool { @@ -292,7 +223,7 @@ func (mem *PriorityMempool) Flush() { // // Safe for concurrent use by multiple goroutines. func (mem *PriorityMempool) TxsFront() *clist.CElement { - return mem.getTxByGasPrice(mem.gasPrices[len(mem.gasPrices)-1]).Front() + return mem.txs.Front() } // TxsWaitChan returns a channel to wait on transactions. It will be closed @@ -301,7 +232,7 @@ func (mem *PriorityMempool) TxsFront() *clist.CElement { // // Safe for concurrent use by multiple goroutines. func (mem *PriorityMempool) TxsWaitChan() <-chan struct{} { - return nil + return mem.txs.WaitChan() } // It blocks if we're waiting on Update() or Reap(). @@ -352,10 +283,10 @@ func (mem *PriorityMempool) CheckTx(tx types.Tx, cb func(*abci.Response), txInfo // Record a new sender for a tx we've already seen. // Note it's possible a tx is still in the cache but no longer in the mempool // (eg. after committing a block, txs are removed from mempool but not cache), - // so we only record the sender for txs still in the tmpool. + // so we only record the sender for txs still in the mempool. if e, ok := mem.txsMap.Load(TxKey(tx)); ok { - memTx := e.(*clist.CElement).Value.(*mempoolTx) - memTx.senders.LoadOrStore(txInfo.SenderID, true) + memTx := e.(*clist.CElement).Value.(*tmpool.MempoolTx) + memTx.Senders.LoadOrStore(txInfo.SenderID, true) // TODO: consider punishing peer for dups, // its non-trivial since invalid txs can become valid, // but they can spam the same tx with little cost to them atm. @@ -424,78 +355,35 @@ func (mem *PriorityMempool) reqResCb( } } -func (mem *PriorityMempool) getTxByGasPrice(gp uint32) *clist.CList { - mem.txsmx.RLock() - defer mem.txsmx.RUnlock() - return mem.txs[gp] -} - -func (mem *PriorityMempool) addGasPrice(gp uint32) { - exists := false - i := sort.Search(len(mem.gasPrices), func(i int) bool { - if mem.gasPrices[i] == gp { - exists = true - } - return mem.gasPrices[i] > gp - }) - - if exists { - return - } - - mem.gasPrices = append(mem.gasPrices, 0) - copy(mem.gasPrices[i+1:], mem.gasPrices[i:]) - mem.gasPrices[i] = gp -} - -func (mem *PriorityMempool) removeGasPrice(gp uint32) { - key := 0 - for i, v := range mem.gasPrices { - if v == gp { - key = i - break - } - } - - mem.gasPrices = append(mem.gasPrices[:key], mem.gasPrices[key+1:]...) -} - // Called from: // - resCbFirstTime (lock not held) if tx is valid -func (mem *PriorityMempool) addTx(memTx *mempoolTx) { - tx, err := mem.executor.DecodeFromBytes(memTx.tx) // TODO: handle error +func (mem *PriorityMempool) addTx(memTx *tmpool.MempoolTx) { + tx, err := mem.executor.DecodeFromBytes(memTx.Tx) // TODO: handle error if err != nil { - panic(fmt.Sprintf("failed to decode tx: %X", memTx.tx)) + panic(fmt.Sprintf("failed to decode tx: %X", memTx.Tx)) } - mem.txsmx.Lock() - if _, ok := mem.txs[tx.GasPrice]; !ok { - mem.txs[tx.GasPrice] = clist.New() + mem.txsgpmu.Lock() + if _, ok := mem.txsByGas[tx.GasPrice]; !ok { + mem.txsByGas[tx.GasPrice] = make(map[[32]byte]*tmpool.MempoolTx) } - - e := mem.txs[tx.GasPrice].PushBack(memTx) - mem.txsmx.Unlock() - - mem.incrementTxsCounter(tx.GasPrice) + mem.txsByGas[tx.GasPrice][TxKey(memTx.Tx)] = memTx + mem.txsgpmu.Unlock() + mem.minterTxMap.Store(TxKey(memTx.Tx), tx) mem.addGasPrice(tx.GasPrice) - mem.txsMap.Store(TxKey(memTx.tx), e) - atomic.AddInt64(&mem.txsBytes, int64(len(memTx.tx))) - mem.metrics.TxSizeBytes.Observe(float64(len(memTx.tx))) + e := mem.txs.PushBack(memTx) + mem.txsMap.Store(TxKey(memTx.Tx), e) + atomic.AddInt64(&mem.txsBytes, int64(len(memTx.Tx))) + mem.metrics.TxSizeBytes.Observe(float64(len(memTx.Tx))) } // Called from: // - Update (lock held) if tx was committed // - resCbRecheck (lock not held) if tx was invalidated func (mem *PriorityMempool) removeTx(tx types.Tx, elem *clist.CElement, removeFromCache bool) { - decodedTx, _ := mem.executor.DecodeFromBytes(tx) - - mem.txsmx.Lock() - mem.txs[decodedTx.GasPrice].Remove(elem) - mem.txsmx.Unlock() - - mem.decrementTxsCounter(decodedTx.GasPrice) - + mem.removeTxFromTxsGasPriceMap(tx) + mem.txs.Remove(elem) elem.DetachPrev() mem.txsMap.Delete(TxKey(tx)) atomic.AddInt64(&mem.txsBytes, int64(-len(tx))) @@ -508,9 +396,9 @@ func (mem *PriorityMempool) removeTx(tx types.Tx, elem *clist.CElement, removeFr // RemoveTxByKey removes a transaction from the mempool by its TxKey index. func (mem *PriorityMempool) RemoveTxByKey(txKey [TxKeySize]byte, removeFromCache bool) { if e, ok := mem.txsMap.Load(txKey); ok { - memTx := e.(*clist.CElement).Value.(*mempoolTx) + memTx := e.(*clist.CElement).Value.(*tmpool.MempoolTx) if memTx != nil { - mem.removeTx(memTx.tx, e.(*clist.CElement), removeFromCache) + mem.removeTx(memTx.Tx, e.(*clist.CElement), removeFromCache) } } } @@ -557,17 +445,17 @@ func (mem *PriorityMempool) resCbFirstTime( return } - memTx := &mempoolTx{ - height: mem.height, - gasWanted: r.CheckTx.GasWanted, - tx: tx, + memTx := &tmpool.MempoolTx{ + Height: mem.height, + GasWanted: r.CheckTx.GasWanted, + Tx: tx, } - memTx.senders.Store(peerID, true) + memTx.Senders.Store(peerID, true) mem.addTx(memTx) mem.logger.Debug("added good transaction", "tx", txID(tx), "res", r, - "height", memTx.height, + "height", memTx.Height, "total", mem.Size(), ) mem.notifyTxsAvailable() @@ -594,11 +482,11 @@ func (mem *PriorityMempool) resCbRecheck(req *abci.Request, res *abci.Response) switch r := res.Value.(type) { case *abci.Response_CheckTx: tx := req.GetCheckTx().Tx - memTx := mem.recheckCursor.Value.(*mempoolTx) - if !bytes.Equal(tx, memTx.tx) { + memTx := mem.recheckCursor.Value.(*tmpool.MempoolTx) + if !bytes.Equal(tx, memTx.Tx) { panic(fmt.Sprintf( "Unexpected tx response from proxy during recheck\nExpected %X, got %X", - memTx.tx, + memTx.Tx, tx)) } var postCheckErr error @@ -617,19 +505,6 @@ func (mem *PriorityMempool) resCbRecheck(req *abci.Request, res *abci.Response) mem.recheckCursor = nil } else { mem.recheckCursor = mem.recheckCursor.Next() - if mem.recheckCursor == nil { - tx, _ := mem.executor.DecodeFromBytes(memTx.tx) - for k, v := range mem.gasPrices { - if v == tx.GasPrice { - if k == 0 { - break - } - - mem.recheckCursor = mem.getTxByGasPrice(mem.gasPrices[k-1]).Front() - break - } - } - } } if mem.recheckCursor == nil { // Done! @@ -674,13 +549,11 @@ func (mem *PriorityMempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs // TODO: we will get a performance boost if we have a good estimate of avg // size per tx, and set the initial capacity based off of that. // txs := make([]types.Tx, 0, tmmath.MinInt(mem.txs.Len(), max/mem.avgTxSize)) - gasPrices, txCount := mem.txsByGasPrices() - txs := make([]types.Tx, 0, txCount) - for _, gp := range gasPrices { - for e := mem.getTxByGasPrice(gp).Front(); e != nil; e = e.Next() { - memTx := e.Value.(*mempoolTx) + txs := make([]types.Tx, 0, mem.txs.Len()) - dataSize := types.ComputeProtoSizeForTxs(append(txs, memTx.tx)) + for _, gp := range mem.gasPrices { + for _, memTx := range mem.getTxsByGas(gp) { + dataSize := types.ComputeProtoSizeForTxs(append(txs, memTx.Tx)) // Check total size requirement if maxBytes > -1 && dataSize > maxBytes { @@ -690,13 +563,12 @@ func (mem *PriorityMempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs // If maxGas is negative, skip this check. // Since newTotalGas < masGas, which // must be non-negative, it follows that this won't overflow. - newTotalGas := totalGas + memTx.gasWanted + newTotalGas := totalGas + memTx.GasWanted if maxGas > -1 && newTotalGas > maxGas { return txs } - totalGas = newTotalGas - txs = append(txs, memTx.tx) + txs = append(txs, memTx.Tx) } } @@ -708,19 +580,15 @@ func (mem *PriorityMempool) ReapMaxTxs(max int) types.Txs { mem.updateMtx.RLock() defer mem.updateMtx.RUnlock() - gasPrices, txCount := mem.txsByGasPrices() if max < 0 { - max = int(txCount) + max = mem.txs.Len() } - txs := make([]types.Tx, 0, tmmath.MinInt(int(txCount), max)) - for _, gp := range gasPrices { - for e := mem.getTxByGasPrice(gp).Front(); e != nil && len(txs) <= max; e = e.Next() { - memTx := e.Value.(*mempoolTx) - txs = append(txs, memTx.tx) - } + txs := make([]types.Tx, 0, tmmath.MinInt(mem.txs.Len(), max)) + for e := mem.txs.Front(); e != nil && len(txs) <= max; e = e.Next() { + memTx := e.Value.(*tmpool.MempoolTx) + txs = append(txs, memTx.Tx) } - return txs } @@ -752,7 +620,7 @@ func (mem *PriorityMempool) Update( mem.cache.Remove(tx) } - // Remove committed tx from the tmpool. + // Remove committed tx from the mempool. // // Note an evil proposer can drop valid txs! // Mempool before: @@ -792,40 +660,76 @@ func (mem *PriorityMempool) recheckTxs() { panic("recheckTxs is called, but the mempool is empty") } - // TODO: handle recheck - mem.recheckCursor = mem.getTxByGasPrice(mem.gasPrices[len(mem.gasPrices)-1]).Front() - mem.recheckEnd = mem.getTxByGasPrice(mem.gasPrices[0]).Back() + mem.recheckCursor = mem.txs.Front() + mem.recheckEnd = mem.txs.Back() // Push txs to proxyAppConn // NOTE: globalCb may be called concurrently. - gasPrices, _ := mem.txsByGasPrices() - for _, gp := range gasPrices { - for e := mem.getTxByGasPrice(gp).Front(); e != nil; e = e.Next() { - memTx := e.Value.(*mempoolTx) - mem.proxyAppConn.CheckTxAsync(abci.RequestCheckTx{ - Tx: memTx.tx, - Type: abci.CheckTxType_Recheck, - }) - } + for e := mem.txs.Front(); e != nil; e = e.Next() { + memTx := e.Value.(*tmpool.MempoolTx) + mem.proxyAppConn.CheckTxAsync(abci.RequestCheckTx{ + Tx: memTx.Tx, + Type: abci.CheckTxType_Recheck, + }) } mem.proxyAppConn.FlushAsync() } -//-------------------------------------------------------------------------------- +// Add new gas price to list of available gas prices +func (mem *PriorityMempool) addGasPrice(gp uint32) { + exists := false + i := sort.Search(len(mem.gasPrices), func(i int) bool { + if mem.gasPrices[i] == gp { + exists = true + } + return mem.gasPrices[i] < gp + }) -// mempoolTx is a transaction that successfully ran -type mempoolTx struct { - height int64 // height that this tx had been validated in - gasWanted int64 // amount of gas this tx states it will require - tx types.Tx // + if exists { + return + } + + mem.gasPrices = append(mem.gasPrices, 0) + copy(mem.gasPrices[i+1:], mem.gasPrices[i:]) + mem.gasPrices[i] = gp +} - // ids of peers who've sent us this tx (as a map for quick lookups). - // senders: PeerID -> bool - senders sync.Map +// Remove gas price from list of available gas prices +func (mem *PriorityMempool) removeGasPrice(gp uint32) { + key := 0 + for i, v := range mem.gasPrices { + if v == gp { + key = i + break + } + } + + mem.gasPrices = append(mem.gasPrices[:key], mem.gasPrices[key+1:]...) +} + +// Get transaction gas price from map by key +func (mem *PriorityMempool) getTxGasPriceFromMap(tx types.Tx) uint32 { + data, _ := mem.minterTxMap.Load(TxKey(tx)) + return data.(*transaction.Transaction).GasPrice +} + +// Remove transaction from map +func (mem *PriorityMempool) removeTxFromTxsGasPriceMap(tx types.Tx) { + mem.txsgpmu.Lock() + defer mem.txsgpmu.Unlock() + + gp := mem.getTxGasPriceFromMap(tx) + delete(mem.txsByGas[gp], TxKey(tx)) + + if len(mem.txsByGas[gp]) == 0 { + mem.removeGasPrice(gp) + } } -// Height returns the height for this transaction -func (memTx *mempoolTx) Height() int64 { - return atomic.LoadInt64(&memTx.height) +// Get transactions map from list by gas +func (mem *PriorityMempool) getTxsByGas(gp uint32) map[[32]byte]*tmpool.MempoolTx { + mem.txsgpmu.RLock() + defer mem.txsgpmu.RUnlock() + return mem.txsByGas[gp] } diff --git a/coreV2/mempool/priority_mempool_test.go b/coreV2/mempool/priority_mempool_test.go index 11b54b997..b52e2719c 100644 --- a/coreV2/mempool/priority_mempool_test.go +++ b/coreV2/mempool/priority_mempool_test.go @@ -1,8 +1,8 @@ package mempool import ( + "crypto/ecdsa" "crypto/sha256" - "encoding/binary" "fmt" "github.com/MinterTeam/minter-go-node/coreV2/transaction" "github.com/MinterTeam/minter-go-node/coreV2/types" @@ -23,7 +23,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/abci/example/counter" + "github.com/MinterTeam/minter-go-node/tests/example/counter" "github.com/tendermint/tendermint/abci/example/kvstore" abciserver "github.com/tendermint/tendermint/abci/server" abci "github.com/tendermint/tendermint/abci/types" @@ -73,26 +73,55 @@ func ensureFire(t *testing.T, ch <-chan struct{}, timeoutMS int) { } } -func createTx(t *testing.T, bytesLen uint64) []byte { - encodedData, err := rlp.EncodeToBytes(transaction.SendData{ +func createTx(bytesLen uint64, privKey *ecdsa.PrivateKey) []byte { + encodedData, _ := rlp.EncodeToBytes(transaction.SendData{ Coin: types.GetBaseCoinID(), To: [20]byte{1}, Value: helpers.BipToPip(big.NewInt(10)), }) - if err != nil { - t.Fatal(err) + payload := []byte{0x01, 0x01} + for i := bytesLen - 116; i > 0; i-- { + payload = append(payload, 0x01) + } + + tx := transaction.Transaction{ + Nonce: uint64(1), + ChainID: types.CurrentChainID, + GasPrice: 1, + GasCoin: types.GetBaseCoinID(), + Type: transaction.TypeSend, + Data: encodedData, + SignatureType: transaction.SigTypeSingle, + Payload: payload, + } + + if privKey == nil { + privKey, _ = crypto.GenerateKey() } + tx.Sign(privKey) + txBytes, _ := tx.Serialize() + return txBytes +} + +func createTxWithRandomGas(bytesLen uint64, privKey *ecdsa.PrivateKey) []byte { + encodedData, _ := rlp.EncodeToBytes(transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: [20]byte{1}, + Value: helpers.BipToPip(big.NewInt(10)), + }) + payload := []byte{0x01, 0x01} for i := bytesLen - 116; i > 0; i-- { payload = append(payload, 0x01) } + gp := tmrand.Intn(200) tx := transaction.Transaction{ Nonce: uint64(1), ChainID: types.CurrentChainID, - GasPrice: 1, + GasPrice: uint32(gp), GasCoin: types.GetBaseCoinID(), Type: transaction.TypeSend, Data: encodedData, @@ -100,11 +129,11 @@ func createTx(t *testing.T, bytesLen uint64) []byte { Payload: payload, } - privKey, _ := crypto.GenerateKey() - if err := tx.Sign(privKey); err != nil { - t.Fatal(err) + if privKey == nil { + privKey, _ = crypto.GenerateKey() } + tx.Sign(privKey) txBytes, _ := tx.Serialize() return txBytes } @@ -113,7 +142,7 @@ func checkTxs(t *testing.T, mempool tmpool.Mempool, count int, peerID uint16) tm txs := make(tmtypes.Txs, count) txInfo := tmpool.TxInfo{SenderID: peerID} for i := 0; i < count; i++ { - txBytes := createTx(t, 116) + txBytes := createTx(116, nil) txs[i] = txBytes if err := mempool.CheckTx(txBytes, nil, txInfo); err != nil { // Skip invalid txs. @@ -136,12 +165,12 @@ func TestReapMaxBytesMaxGas(t *testing.T) { // Ensure gas calculation behaves as expected checkTxs(t, mempool, 1, tmpool.UnknownPeerID) - tx0 := mempool.txs[1].Front().Value.(*mempoolTx) + tx0 := mempool.txs.Front().Value.(*tmpool.MempoolTx) //// assert that kv store has gas wanted = 1. - require.Equal(t, app.CheckTx(abci.RequestCheckTx{Tx: tx0.tx}).GasWanted, int64(1), "KVStore had a gas value neq to 1") - require.Equal(t, tx0.gasWanted, int64(1), "transactions gas was set incorrectly") + require.Equal(t, app.CheckTx(abci.RequestCheckTx{Tx: tx0.Tx}).GasWanted, int64(1), "KVStore had a gas value neq to 1") + require.Equal(t, tx0.GasWanted, int64(1), "transactions gas was set incorrectly") //// ensure each tx is 116 bytes long - require.Equal(t, len(tx0.tx), 116, "Tx is longer than 116 bytes") + require.Equal(t, len(tx0.Tx), 116, "Tx is longer than 116 bytes") mempool.Flush() // each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs. @@ -165,7 +194,7 @@ func TestReapMaxBytesMaxGas(t *testing.T) { {20, 1180, -1, 10}, {20, 1180, 10, 10}, {20, 1180, 15, 10}, - + // {20, 20000, -1, 20}, {20, 20000, 5, 5}, {20, 20000, 30, 20}, @@ -179,6 +208,33 @@ func TestReapMaxBytesMaxGas(t *testing.T) { } } +func TestReapMaxBytesMaxGasPriority(t *testing.T) { + app := kvstore.NewApplication() + cc := proxy.NewLocalClientCreator(app) + mempool, cleanup := newMempoolWithApp(cc) + defer cleanup() + + txInfo := tmpool.TxInfo{SenderID: tmpool.UnknownPeerID} + for i := 0; i < 1000; i++ { + if err := mempool.CheckTx(createTxWithRandomGas(116, nil), nil, txInfo); err != nil { + if tmpool.IsPreCheckError(err) { + continue + } + } + } + + txs := mempool.ReapMaxBytesMaxGas(10000000000, 10000000000) + assert.Equal(t, 1000, len(txs)) + + executor := transaction.NewExecutor(transaction.GetData) + + for i := 0; i <= len(txs)-2; i++ { + data, _ := executor.DecodeFromBytes(txs[i]) + data1, _ := executor.DecodeFromBytes(txs[i+1]) + assert.Equal(t, true, data1.GasPrice <= data.GasPrice) + } +} + func TestMempoolFilters(t *testing.T) { app := kvstore.NewApplication() cc := proxy.NewLocalClientCreator(app) @@ -226,7 +282,7 @@ func TestMempoolUpdate(t *testing.T) { // 1. Adds valid txs to the cache { - tx := createTx(t, 116) + tx := createTx(116, nil) err := mempool.Update(1, []tmtypes.Tx{tx}, abciResponses(1, abci.CodeTypeOK), nil, nil) require.NoError(t, err) err = mempool.CheckTx(tx, nil, tmpool.TxInfo{}) @@ -237,7 +293,7 @@ func TestMempoolUpdate(t *testing.T) { // 2. Removes valid txs from the mempool { - tx := createTx(t, 117) + tx := createTx(117, nil) err := mempool.CheckTx(tx, nil, tmpool.TxInfo{}) require.NoError(t, err) err = mempool.Update(1, []tmtypes.Tx{tx}, abciResponses(1, abci.CodeTypeOK), nil, nil) @@ -247,7 +303,7 @@ func TestMempoolUpdate(t *testing.T) { // 3. Removes invalid transactions from the cache and the mempool (if present) { - tx := createTx(t, 118) + tx := createTx(118, nil) err := mempool.CheckTx(tx, nil, tmpool.TxInfo{}) require.NoError(t, err) err = mempool.Update(1, []tmtypes.Tx{tx}, abciResponses(1, 1), nil, nil) @@ -260,7 +316,7 @@ func TestMempoolUpdate(t *testing.T) { } func TestMempool_KeepInvalidTxsInCache(t *testing.T) { - app := counter.NewApplication(true) + app := counter.NewApplication(true, nil) cc := proxy.NewLocalClientCreator(app) wcfg := cfg.DefaultConfig() wcfg.Mempool.KeepInvalidTxsInCache = true @@ -269,8 +325,8 @@ func TestMempool_KeepInvalidTxsInCache(t *testing.T) { // 1. An invalid transaction must remain in the cache after Update { - a := createTx(t, 116) - b := createTx(t, 116) + a := createTx(116, nil) + b := createTx(116, nil) err := mempool.CheckTx(b, nil, tmpool.TxInfo{}) require.NoError(t, err) @@ -296,7 +352,7 @@ func TestMempool_KeepInvalidTxsInCache(t *testing.T) { // 2. An invalid transaction must remain in the cache { - a := createTx(t, 116) + a := createTx(116, nil) // remove a from the cache to test (2) mempool.cache.Remove(a) @@ -356,7 +412,7 @@ func TestTxsAvailable(t *testing.T) { } func TestSerialReap(t *testing.T) { - app := counter.NewApplication(true) + app := counter.NewApplication(true, nil) app.SetOption(abci.RequestSetOption{Key: "serial", Value: "on"}) cc := proxy.NewLocalClientCreator(app) @@ -369,12 +425,14 @@ func TestSerialReap(t *testing.T) { err := appConnCon.Start() require.Nil(t, err) + priv, _ := crypto.GenerateKey() + cacheMap := make(map[string]struct{}) deliverTxsRange := func(start, end int) { // Deliver some txs. for i := start; i < end; i++ { - // This will succeed - txBytes := createTx(t, 116+uint64(i)) + // This will succeeds + txBytes := createTx(116+uint64(i), priv) err := mempool.CheckTx(txBytes, nil, tmpool.TxInfo{}) _, cached := cacheMap[string(txBytes)] if cached { @@ -398,8 +456,7 @@ func TestSerialReap(t *testing.T) { updateRange := func(start, end int) { txs := make([]tmtypes.Tx, 0) for i := start; i < end; i++ { - txBytes := make([]byte, 8) - binary.BigEndian.PutUint64(txBytes, uint64(i)) + txBytes := createTx(116+uint64(i), priv) txs = append(txs, txBytes) } if err := mempool.Update(0, txs, abciResponses(len(txs), abci.CodeTypeOK), nil, nil); err != nil { @@ -410,8 +467,7 @@ func TestSerialReap(t *testing.T) { commitRange := func(start, end int) { // Deliver some txs. for i := start; i < end; i++ { - txBytes := make([]byte, 8) - binary.BigEndian.PutUint64(txBytes, uint64(i)) + txBytes := createTx(116+uint64(i), priv) res, err := appConnCon.DeliverTxSync(abci.RequestDeliverTx{Tx: txBytes}) if err != nil { t.Errorf("client error committing tx: %v", err) @@ -492,19 +548,19 @@ func TestMempoolCloseWAL(t *testing.T) { require.Equal(t, 1, len(m2), "expecting the wal match in") // 5. Write some contents to the WAL - tx := createTx(t, 116) + tx := createTx(116, nil) err = mempool.CheckTx(tx, nil, tmpool.TxInfo{}) require.NoError(t, err) walFilepath := mempool.wal.Path sum1 := checksumFile(walFilepath, t) //// 6. Sanity check to ensure that the written TX matches the expectation. - //require.Equal(t, sum1, checksumIt(tx), "foo with a newline should be written") + require.Equal(t, sum1, checksumIt(append(tx, []byte("\n")...)), "foo with a newline should be written") // 7. Invoke CloseWAL() and ensure it discards the // WAL thus any other write won't go through. mempool.CloseWAL() - err = mempool.CheckTx(createTx(t, 117), nil, tmpool.TxInfo{}) + err = mempool.CheckTx(createTx(117, nil), nil, tmpool.TxInfo{}) require.NoError(t, err) sum2 := checksumFile(walFilepath, t) require.Equal(t, sum1, sum2, "expected no change to the WAL after invoking CloseWAL() since it was discarded") @@ -524,24 +580,25 @@ func TestMempool_CheckTxChecksTxSize(t *testing.T) { maxTxSize := mempl.config.MaxTxBytes testCases := []struct { - len int - err bool + len int + err bool + experr int }{ // check small txs. no error - 0: {10, false}, - 1: {1000, false}, - 2: {1000000, false}, + 0: {10, false, 0}, + 1: {1000, false, 0}, + 2: {1000000, false, 0}, // check around maxTxSize - 3: {maxTxSize - 1, false}, - 4: {maxTxSize, false}, - 5: {maxTxSize + 1, true}, + 3: {maxTxSize - 122, false, 0}, + 4: {maxTxSize - 121, false, 0}, + 5: {maxTxSize - 120, true, maxTxSize + 1}, } for i, testCase := range testCases { caseString := fmt.Sprintf("case %d, len %d", i, testCase.len) - tx := createTx(t, uint64(testCase.len)) + tx := createTx(uint64(116+testCase.len), nil) err := mempl.CheckTx(tx, nil, tmpool.TxInfo{}) bv := gogotypes.BytesValue{Value: tx} @@ -552,7 +609,7 @@ func TestMempool_CheckTxChecksTxSize(t *testing.T) { if !testCase.err { require.NoError(t, err, caseString) } else { - require.Equal(t, err, ErrTxTooLarge{maxTxSize, testCase.len}, caseString) + require.Equal(t, err, ErrTxTooLarge{maxTxSize, testCase.experr}, caseString) } } } @@ -569,7 +626,7 @@ func TestMempoolTxsBytes(t *testing.T) { assert.EqualValues(t, 0, mempool.TxsBytes()) // 2. len(tx) after CheckTx - tx1 := createTx(t, 116) + tx1 := createTx(116, nil) err := mempool.CheckTx(tx1, nil, tmpool.TxInfo{}) require.NoError(t, err) assert.EqualValues(t, 116, mempool.TxsBytes()) @@ -580,7 +637,7 @@ func TestMempoolTxsBytes(t *testing.T) { assert.EqualValues(t, 0, mempool.TxsBytes()) // 4. zero after Flush - err = mempool.CheckTx(createTx(t, 117), nil, tmpool.TxInfo{}) + err = mempool.CheckTx(createTx(117, nil), nil, tmpool.TxInfo{}) require.NoError(t, err) assert.EqualValues(t, 117, mempool.TxsBytes()) @@ -588,51 +645,55 @@ func TestMempoolTxsBytes(t *testing.T) { assert.EqualValues(t, 0, mempool.TxsBytes()) // 5. ErrMempoolIsFull is returned when/if MaxTxsBytes limit is reached. - err = mempool.CheckTx(createTx(t, 126), nil, tmpool.TxInfo{}) + err = mempool.CheckTx(createTx(126, nil), nil, tmpool.TxInfo{}) require.NoError(t, err) - err = mempool.CheckTx(createTx(t, 117), nil, tmpool.TxInfo{}) + err = mempool.CheckTx(createTx(117, nil), nil, tmpool.TxInfo{}) if assert.Error(t, err) { assert.IsType(t, ErrMempoolIsFull{}, err) } // 6. zero after tx is rechecked and removed due to not being valid anymore - app2 := counter.NewApplication(true) + app2 := counter.NewApplication(true, transaction.NewExecutor(transaction.GetData)) cc = proxy.NewLocalClientCreator(app2) mempool, cleanup = newMempoolWithApp(cc) defer cleanup() - //tx := createTx(t, 124) - //err = mempool.CheckTx(tx, nil, tmpool.TxInfo{}) - //require.NoError(t, err) - //assert.EqualValues(t, 124, mempool.TxsBytes()) - - //appConnCon, _ := cc.NewABCIClient() - //appConnCon.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "consensus")) - //err = appConnCon.Start() - //require.Nil(t, err) - //t.Cleanup(func() { - // if err := appConnCon.Stop(); err != nil { - // t.Error(err) - // } - //}) - //res, err := appConnCon.DeliverTxSync(abci.RequestDeliverTx{Tx: tx}) - //require.NoError(t, err) - //require.EqualValues(t, uint32(0), res.Code) - //res2, err := appConnCon.CommitSync() - //require.NoError(t, err) - //require.NotEmpty(t, res2.Data) - // - //// Pretend like we committed nothing so txBytes gets rechecked and removed. - //err = mempool.Update(1, []tmtypes.Tx{}, abciResponses(0, abci.CodeTypeOK), nil, nil) - //require.NoError(t, err) - //assert.EqualValues(t, 0, mempool.TxsBytes()) - - // 7. Test RemoveTxByKey function - tx := createTx(t, 123) + app2.TxCount = 1 + tx := createTx(124, nil) + err = mempool.CheckTx(tx, nil, tmpool.TxInfo{}) + require.NoError(t, err) + assert.EqualValues(t, 124, mempool.TxsBytes()) + + appConnCon, _ := cc.NewABCIClient() + appConnCon.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "consensus")) + err = appConnCon.Start() + require.Nil(t, err) + t.Cleanup(func() { + if err := appConnCon.Stop(); err != nil { + t.Error(err) + } + }) + res, err := appConnCon.DeliverTxSync(abci.RequestDeliverTx{Tx: tx}) + require.NoError(t, err) + require.EqualValues(t, uint32(0), res.Code) + res2, err := appConnCon.CommitSync() + require.NoError(t, err) + require.NotEmpty(t, res2.Data) + + // Pretend like we committed nothing so txBytes gets rechecked and removed. + err = mempool.Update(1, []tmtypes.Tx{}, abciResponses(0, abci.CodeTypeOK), nil, nil) + require.NoError(t, err) + assert.EqualValues(t, 0, mempool.TxsBytes()) + + // 7. Test RemoveTxByK ey function + mempool, cleanup = newMempoolWithAppAndConfig(proxy.NewLocalClientCreator(app), config) + defer cleanup() + + tx = createTx(123, nil) err = mempool.CheckTx(tx, nil, tmpool.TxInfo{}) require.NoError(t, err) assert.EqualValues(t, 123, mempool.TxsBytes()) - mempool.RemoveTxByKey(TxKey(createTx(t, 124)), true) + mempool.RemoveTxByKey(TxKey(createTx(124, nil)), true) assert.EqualValues(t, 123, mempool.TxsBytes()) mempool.RemoveTxByKey(TxKey(tx), true) assert.EqualValues(t, 0, mempool.TxsBytes()) @@ -660,7 +721,7 @@ func TestMempoolRemoteAppConcurrency(t *testing.T) { nTxs := 10 txs := make([]tmtypes.Tx, nTxs) for i := 0; i < nTxs; i++ { - txs[i] = createTx(t, 116) + txs[i] = createTx(116, nil) } // simulate a group of peers sending them over and over diff --git a/coreV2/minter/blockchain.go b/coreV2/minter/blockchain.go index 9dfb1f71b..13583890b 100644 --- a/coreV2/minter/blockchain.go +++ b/coreV2/minter/blockchain.go @@ -79,6 +79,10 @@ type Blockchain struct { stopOk chan struct{} } +func (blockchain *Blockchain) GetCurrentRewards() *big.Int { + return blockchain.rewards +} + // NewMinterBlockchain creates Minter Blockchain instance, should be only called once func NewMinterBlockchain(storages *utils.Storage, cfg *config.Config, ctx context.Context, period uint64) *Blockchain { // Initiate Application DB. Used for persisting data like current block, validators, etc. @@ -110,7 +114,7 @@ func NewMinterBlockchain(storages *utils.Storage, cfg *config.Config, ctx contex knownUpdates: map[string]struct{}{ "": {}, // default version v230: {}, // add more for update - // v240: {}, // commissions + v250: {}, // commissions and mempool }, executor: GetExecutor(""), } @@ -126,8 +130,8 @@ func graceForUpdate(height uint64) *upgrades.GracePeriod { func GetExecutor(v string) transaction.ExecutorTx { switch v { - // case v240: - // return transaction.NewExecutor(transaction.GetDataV240) + case v250: + return transaction.NewExecutorV250(transaction.GetDataV250) case v230: return transaction.NewExecutor(transaction.GetDataV230) default: @@ -138,7 +142,7 @@ func GetExecutor(v string) transaction.ExecutorTx { const haltBlockV210 = 3431238 const updateBlockV240 = 4448826 const v230 = "v230" -const v240 = "v240" +const v250 = "v250" func (blockchain *Blockchain) initState() { initialHeight := blockchain.appDB.GetStartHeight() @@ -182,10 +186,9 @@ func (blockchain *Blockchain) InitChain(req abciTypes.RequestInitChain) abciType initialHeight := uint64(req.InitialHeight) - 1 blockchain.appDB.SetStartHeight(initialHeight) + blockchain.appDB.AddVersion(genesisState.Version, initialHeight) blockchain.initState() - // todo: use genesisState.Version - if err := blockchain.stateDeliver.Import(genesisState); err != nil { panic(err) } @@ -201,6 +204,7 @@ func (blockchain *Blockchain) InitChain(req abciTypes.RequestInitChain) abciType blockchain.appDB.SetLastHeight(lastHeight) blockchain.appDB.SaveStartHeight() + blockchain.appDB.SaveVersions() defer blockchain.appDB.FlushValidators() return abciTypes.ResponseInitChain{ @@ -401,6 +405,8 @@ func (blockchain *Blockchain) EndBlock(req abciTypes.RequestEndBlock) abciTypes. VoteCommission: price.VoteCommission.String(), VoteUpdate: price.VoteUpdate.String(), FailedTx: price.FailedTxPrice().String(), + AddLimitOrder: price.AddLimitOrderPrice().String(), + RemoveLimitOrder: price.RemoveLimitOrderPrice().String(), }) } blockchain.stateDeliver.Commission.Delete(height) diff --git a/coreV2/minter/minter.go b/coreV2/minter/minter.go index daffc591e..d22fb9322 100644 --- a/coreV2/minter/minter.go +++ b/coreV2/minter/minter.go @@ -2,6 +2,11 @@ package minter import ( "fmt" + "log" + "math/big" + "os" + "sync/atomic" + "github.com/MinterTeam/minter-go-node/coreV2/appdb" eventsdb "github.com/MinterTeam/minter-go-node/coreV2/events" "github.com/MinterTeam/minter-go-node/coreV2/rewards" @@ -15,10 +20,6 @@ import ( abciTypes "github.com/tendermint/tendermint/abci/types" tmNode "github.com/tendermint/tendermint/node" rpc "github.com/tendermint/tendermint/rpc/client/local" - "log" - "math/big" - "os" - "sync/atomic" ) func (blockchain *Blockchain) RpcClient() *rpc.Local { @@ -48,7 +49,7 @@ func (blockchain *Blockchain) stop() { blockchain.stopped = true if blockchain.tmNode == nil { blockchain.Close() - os.Exit(0) + os.Exit(1) } else { go func() { log.Println("Stopping Node") diff --git a/coreV2/minter/minter_test.go b/coreV2/minter/minter_test.go index b3cf1e468..16d93a52d 100644 --- a/coreV2/minter/minter_test.go +++ b/coreV2/minter/minter_test.go @@ -52,8 +52,7 @@ func initTestNode(t *testing.T, initialHeight int64) (*Blockchain, *rpc.Local, * cfg.P2P.PersistentPeers = "" cfg.DBBackend = "memdb" - pv := privval.GenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()) - pv.Save() + pv := privval.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()) ctx, cancelFunc := context.WithCancel(context.Background()) @@ -62,8 +61,6 @@ func initTestNode(t *testing.T, initialHeight int64) (*Blockchain, *rpc.Local, * if err != nil { t.Fatal(err) } - app.appDB.AddVersion("v230", 0) - app.appDB.SaveVersions() node, err := tmNode.NewNode( cfg, @@ -111,7 +108,7 @@ func initTestNode(t *testing.T, initialHeight int64) (*Blockchain, *rpc.Local, * return app, tmCli, pv, func() { cancelFunc() if err := app.WaitStop(); err != nil { - t.Error(err) + t.Skip(err) } } } @@ -170,7 +167,11 @@ func TestBlockchain_UpdateCommission(t *testing.T) { BurnToken: helpers.StringToBigInt("10000000000000000000"), VoteCommission: helpers.StringToBigInt("100000000000000000000"), VoteUpdate: helpers.StringToBigInt("100000000000000000000"), - More: nil, + More: []*big.Int{ + helpers.StringToBigInt("1000000000000000000"), + helpers.StringToBigInt("1000000000000000000"), + helpers.StringToBigInt("1000000000000000000"), + }, } encodedData, err := rlp.EncodeToBytes(data) @@ -232,21 +233,12 @@ func TestBlockchain_UpdateCommission(t *testing.T) { if len(events) == 0 { t.Fatalf("not found events") } - // for _, event := range events { - // t.Logf("%#v", event) - // } if events[0].Type() != eventsdb.TypeUpdateCommissionsEvent { t.Fatal("not changed") } return case <-time.After(10 * time.Second): t.Fatal("timeout") - // blockchain.lock.RLock() - // exportedState := blockchain.CurrentState().Export() - // blockchain.lock.RUnlock() - // if err := exportedState.Verify(); err != nil { - // t.Fatal(err) - // } return } } @@ -414,7 +406,7 @@ func TestBlockchain_SetStatisticData(t *testing.T) { func TestBlockchain_IsApplicationHalted(t *testing.T) { blockchain, tmCli, pv, _ := initTestNode(t, 0) - // defer cancel() + // defer cancel() // unexpected call to os.Exit(0) during test data := transaction.SetHaltBlockData{ PubKey: types.BytesToPubkey(pv.Key.PubKey.Bytes()[:]), Height: 5, @@ -553,8 +545,6 @@ func TestBlockchain_GetStateForHeightAndDeleteStateVersions(t *testing.T) { t.Fatalf("Failed: %s", "state not deleted") } - blockchain.lock.RLock() - defer blockchain.lock.RUnlock() exportedState := blockchain.CurrentState().Export() if err := exportedState.Verify(); err != nil { t.Fatal(err) @@ -1024,6 +1014,7 @@ func getTestGenesis(pv *privval.FilePV, home string, initialState int64) func() validators, candidates := makeTestValidatorsAndCandidates([]string{string(pv.Key.PubKey.Bytes()[:])}, helpers.BipToPip(big.NewInt(12444011))) appState := types.AppState{ + Version: v250, TotalSlashed: "0", Accounts: []types.Account{ { diff --git a/coreV2/state/accounts/accounts.go b/coreV2/state/accounts/accounts.go index 934433839..3878cb054 100644 --- a/coreV2/state/accounts/accounts.go +++ b/coreV2/state/accounts/accounts.go @@ -190,9 +190,8 @@ func (a *Accounts) GetBalance(address types.Address, coin types.CoinID) *big.Int return big.NewInt(0) } - account.lock.RLock() + account.lock.Lock() balance, ok := account.balances[coin] - account.lock.RUnlock() if !ok { balance = big.NewInt(0) @@ -206,10 +205,9 @@ func (a *Accounts) GetBalance(address types.Address, coin types.CoinID) *big.Int balance = big.NewInt(0).SetBytes(enc) } - account.lock.Lock() account.balances[coin] = balance - account.lock.Unlock() } + account.lock.Unlock() return big.NewInt(0).Set(balance) } diff --git a/coreV2/state/commission/commission.go b/coreV2/state/commission/commission.go index 619795c77..29f025d45 100644 --- a/coreV2/state/commission/commission.go +++ b/coreV2/state/commission/commission.go @@ -126,6 +126,8 @@ func (c *Commission) Export(state *types.AppState) { VoteCommission: p.VoteCommission.String(), VoteUpdate: p.VoteUpdate.String(), FailedTx: p.FailedTxPrice().String(), + AddLimitOrder: p.AddLimitOrderPrice().String(), + RemoveLimitOrder: p.RemoveLimitOrderPrice().String(), }, }) } diff --git a/coreV2/state/commission/model.go b/coreV2/state/commission/model.go index 11a104c18..68ca056e4 100644 --- a/coreV2/state/commission/model.go +++ b/coreV2/state/commission/model.go @@ -53,7 +53,7 @@ type Price struct { VoteCommission *big.Int VoteUpdate *big.Int - // todo: in v250 add FailedTx and AddOrder *big.Int + // todo: in v260 add FailedTx, AddLimitOrder and RemoveLimitOrder *big.Int More []*big.Int `rlp:"tail"` } @@ -65,12 +65,27 @@ func (d *Price) Encode() []byte { return bytes } -func (d *Price) FailedTxPrice() *big.Int { // todo: in v250 use FailedTx +func (d *Price) FailedTxPrice() *big.Int { // todo: in v260 use FailedTx if len(d.More) > 0 { return d.More[0] } return d.Send } + +func (d *Price) AddLimitOrderPrice() *big.Int { // todo: in v260 + if len(d.More) > 1 { + return d.More[1] + } + return d.CreateSwapPool +} + +func (d *Price) RemoveLimitOrderPrice() *big.Int { // todo: in v260 + if len(d.More) > 2 { + return d.More[2] + } + return d.RemoveLiquidity +} + func Decode(s string) *Price { var p Price err := rlp.DecodeBytes([]byte(s), &p) diff --git a/coreV2/state/state.go b/coreV2/state/state.go index 2517d8726..fcec2a0ac 100644 --- a/coreV2/state/state.go +++ b/coreV2/state/state.go @@ -2,6 +2,9 @@ package state import ( "encoding/hex" + "log" + "sync" + eventsdb "github.com/MinterTeam/minter-go-node/coreV2/events" "github.com/MinterTeam/minter-go-node/coreV2/state/accounts" "github.com/MinterTeam/minter-go-node/coreV2/state/app" @@ -22,8 +25,6 @@ import ( "github.com/MinterTeam/minter-go-node/tree" "github.com/cosmos/iavl" db "github.com/tendermint/tm-db" - "log" - "sync" ) type Interface interface { @@ -351,6 +352,15 @@ func (s *State) Import(state types.AppState) error { More: nil, } + if helpers.StringToBigIntOrNil(state.Commission.FailedTx) != nil || + helpers.StringToBigIntOrNil(state.Commission.AddLimitOrder) != nil || + helpers.StringToBigIntOrNil(state.Commission.RemoveLimitOrder) != nil { + com.More = append(com.More, + helpers.StringToBigIntOrNil(state.Commission.FailedTx), + helpers.StringToBigIntOrNil(state.Commission.AddLimitOrder), + helpers.StringToBigIntOrNil(state.Commission.RemoveLimitOrder)) + } + s.Commission.SetNewCommissions(com.Encode()) return nil diff --git a/coreV2/state/swap/swap.go b/coreV2/state/swap/swap.go index 91e1b678c..8f371d74e 100644 --- a/coreV2/state/swap/swap.go +++ b/coreV2/state/swap/swap.go @@ -728,10 +728,11 @@ func (p *Pair) checkSwap(amount0In, amount1In, amount0Out, amount1Out *big.Int) } func (p *Pair) update(amount0, amount1 *big.Int) { + p.markDirty() + p.pairData.Lock() defer p.pairData.Unlock() - p.markDirty() p.Reserve0.Add(p.Reserve0, amount0) p.Reserve1.Add(p.Reserve1, amount1) } diff --git a/coreV2/transaction/buy_swap_pool_v230.go b/coreV2/transaction/buy_swap_pool_v230.go index d06339b5e..0b0a6b7bc 100644 --- a/coreV2/transaction/buy_swap_pool_v230.go +++ b/coreV2/transaction/buy_swap_pool_v230.go @@ -263,7 +263,7 @@ func CheckSwap(rSwap swap.EditableChecker, coinIn CalculateCoin, coinOut Calcula Code: code.MaximumValueToSellReached, Log: fmt.Sprintf( "You wanted to sell maximum %s %s, but currently you need to spend %s %s to complete tx", - valueIn.String(), coinIn.GetFullSymbol(), calculatedAmountToSell.String(), coinOut.GetFullSymbol()), + valueIn.String(), coinIn.GetFullSymbol(), calculatedAmountToSell.String(), coinIn.GetFullSymbol()), Info: EncodeError(code.NewMaximumValueToSellReached(valueIn.String(), calculatedAmountToSell.String(), coinIn.GetFullSymbol(), coinIn.ID().String())), } } diff --git a/coreV2/transaction/buy_swap_pool_v240.go b/coreV2/transaction/buy_swap_pool_v240.go index d6af9690b..86a32a54d 100644 --- a/coreV2/transaction/buy_swap_pool_v240.go +++ b/coreV2/transaction/buy_swap_pool_v240.go @@ -138,7 +138,7 @@ func (data BuySwapPoolDataV240) Run(tx *Transaction, context state.Interface, re return Response{ // todo Code: code.SwapPoolUnknown, Log: fmt.Sprintf("swap pool has reserves %s %s and %d %s, you wanted buy %s %s", reserve0, coinToSellModel.GetFullSymbol(), reserve1, coinToBuyModel.GetFullSymbol(), valueToBuy, coinToSellModel.GetFullSymbol()), - Info: EncodeError(code.NewInsufficientLiquidity(coinToSellModel.ID().String(), valueToBuyCalc.String(), coinToBuyModel.ID().String(), valueToBuy.String(), reserve0.String(), reserve1.String())), + Info: EncodeError(code.NewInsufficientLiquidity(coinToSellModel.ID().String(), "", coinToBuyModel.ID().String(), valueToBuy.String(), reserve0.String(), reserve1.String())), } } valueToBuy = valueToBuyCalc diff --git a/coreV2/transaction/decoder.go b/coreV2/transaction/decoder.go index de3da681a..bdf8ee53c 100644 --- a/coreV2/transaction/decoder.go +++ b/coreV2/transaction/decoder.go @@ -78,7 +78,7 @@ func GetDataV1(txType TxType) (Data, bool) { } } -func GetData(txType TxType) (Data, bool) { return GetDataV240(txType) } +func GetData(txType TxType) (Data, bool) { return GetDataV250(txType) } func GetDataV240(txType TxType) (Data, bool) { switch txType { @@ -141,7 +141,78 @@ func GetDataV240(txType TxType) (Data, bool) { case TypeRecreateToken: return &RecreateTokenData{}, true case TypeVoteCommission: - return &VoteCommissionDataV1{}, true // Ok! + return &VoteCommissionDataV1{}, true + case TypeVoteUpdate: + return &VoteUpdateDataV230{}, true + case TypeCreateSwapPool: + return &CreateSwapPoolData{}, true + default: + return nil, false + } +} + +func GetDataV250(txType TxType) (Data, bool) { + switch txType { + case TypeSend: + return &SendData{}, true + case TypeSellCoin: + return &SellCoinData{}, true + case TypeSellAllCoin: + return &SellAllCoinData{}, true + case TypeBuyCoin: + return &BuyCoinData{}, true + case TypeCreateCoin: + return &CreateCoinData{}, true + case TypeDeclareCandidacy: + return &DeclareCandidacyData{}, true + case TypeDelegate: + return &DelegateData{}, true + case TypeUnbond: + return &UnbondData{}, true + case TypeRedeemCheck: + return &RedeemCheckData{}, true + case TypeSetCandidateOnline: + return &SetCandidateOnData{}, true + case TypeSetCandidateOffline: + return &SetCandidateOffData{}, true + case TypeMultisend: + return &MultisendData{}, true + case TypeCreateMultisig: + return &CreateMultisigData{}, true + case TypeEditCandidate: + return &EditCandidateData{}, true + case TypeSetHaltBlock: + return &SetHaltBlockData{}, true + case TypeRecreateCoin: + return &RecreateCoinData{}, true + case TypeEditCoinOwner: + return &EditCoinOwnerData{}, true + case TypeEditMultisig: + return &EditMultisigData{}, true + case TypeEditCandidatePublicKey: + return &EditCandidatePublicKeyData{}, true + case TypeAddLiquidity: + return &AddLiquidityDataV240{}, true + case TypeRemoveLiquidity: + return &RemoveLiquidityV240{}, true + case TypeSellSwapPool: + return &SellSwapPoolDataV240{}, true + case TypeBuySwapPool: + return &BuySwapPoolDataV240{}, true + case TypeSellAllSwapPool: + return &SellAllSwapPoolDataV240{}, true + case TypeEditCandidateCommission: + return &EditCandidateCommission{}, true + case TypeMintToken: + return &MintTokenData{}, true + case TypeBurnToken: + return &BurnTokenData{}, true + case TypeCreateToken: + return &CreateTokenData{}, true + case TypeRecreateToken: + return &RecreateTokenData{}, true + case TypeVoteCommission: + return &VoteCommissionDataV250{}, true case TypeVoteUpdate: return &VoteUpdateDataV230{}, true case TypeCreateSwapPool: diff --git a/coreV2/transaction/executor_v240.go b/coreV2/transaction/executor_v240.go index 4b3e5fdf2..540dc7e67 100644 --- a/coreV2/transaction/executor_v240.go +++ b/coreV2/transaction/executor_v240.go @@ -30,7 +30,7 @@ type ExecutorV240 struct { decodeTxFunc func(txType TxType) (Data, bool) } -func NewExecutorV240(decodeTxFunc func(txType TxType) (Data, bool)) ExecutorTx { +func NewExecutorV250(decodeTxFunc func(txType TxType) (Data, bool)) ExecutorTx { return &ExecutorV240{decodeTxFunc: decodeTxFunc, Executor: &Executor{decodeTxFunc: decodeTxFunc}} } @@ -67,11 +67,11 @@ func (e *ExecutorV240) RunTx(context state.Interface, rawTx []byte, rewardPool * checkState = state.NewCheckState(context.(*state.State)) } - if !checkState.Coins().Exists(tx.GasCoin) { + if !checkState.Coins().Exists(tx.commissionCoin()) { return Response{ Code: code.CoinNotExists, - Log: fmt.Sprintf("Coin %s not exists", tx.GasCoin), - Info: EncodeError(code.NewCoinNotExists("", tx.GasCoin.String())), + Log: fmt.Sprintf("Coin %s not exists", tx.commissionCoin()), + Info: EncodeError(code.NewCoinNotExists("", tx.commissionCoin().String())), } } @@ -184,7 +184,7 @@ func (e *ExecutorV240) RunTx(context state.Interface, rawTx []byte, rewardPool * if !commissions.Coin.IsBaseCoin() { price = checkState.Swap().GetSwapper(commissions.Coin, types.GetBaseCoinID()).CalculateBuyForSell(price) } - if price == nil { + if price == nil || price.Sign() != 1 { return Response{ Code: code.CommissionCoinNotSufficient, Log: fmt.Sprint("Not possible to pay commission"), @@ -206,12 +206,17 @@ func (e *ExecutorV240) RunTx(context state.Interface, rawTx []byte, rewardPool * if !isCheck && response.Code != 0 { commissionInBaseCoin := big.NewInt(0).Add(commissions.FailedTxPrice(), big.NewInt(0).Mul(big.NewInt(tx.payloadAndServiceDataLen()), commissions.PayloadByte)) - if types.CurrentChainID != types.ChainTestnet || currentBlock > 4451966 { // todo: remove check (need for testnet) - commissionInBaseCoin = tx.MulGasPrice(commissionInBaseCoin) - } + commissionInBaseCoin = tx.MulGasPrice(commissionInBaseCoin) if !commissions.Coin.IsBaseCoin() { commissionInBaseCoin = checkState.Swap().GetSwapper(commissions.Coin, types.GetBaseCoinID()).CalculateBuyForSell(commissionInBaseCoin) + if commissionInBaseCoin == nil || commissionInBaseCoin.Sign() != 1 { + return Response{ + Code: code.CommissionCoinNotSufficient, + Log: fmt.Sprint("Not possible to pay commission"), + Info: EncodeError(code.NewCommissionCoinNotSufficient("", "")), + } + } } commissionPoolSwapper := checkState.Swap().GetSwapper(tx.commissionCoin(), types.GetBaseCoinID()) @@ -251,7 +256,7 @@ func (e *ExecutorV240) RunTx(context state.Interface, rawTx []byte, rewardPool * commission = big.NewInt(0).Set(balance) if isGasCommissionFromPoolSwap { commissionInBaseCoin = commissionPoolSwapper.CalculateBuyForSell(commission) - if commissionInBaseCoin == nil || commissionInBaseCoin.Sign() == 0 { + if commissionInBaseCoin == nil || commissionInBaseCoin.Sign() != 1 { return Response{ Code: code.CommissionCoinNotSufficient, Log: fmt.Sprint("Not possible to pay commission"), diff --git a/coreV2/transaction/executor_v240_test.go b/coreV2/transaction/executor_v240_test.go new file mode 100644 index 000000000..eac19684a --- /dev/null +++ b/coreV2/transaction/executor_v240_test.go @@ -0,0 +1,71 @@ +package transaction + +import ( + "math/big" + "sync" + "testing" + + "github.com/MinterTeam/minter-go-node/coreV2/types" + "github.com/MinterTeam/minter-go-node/crypto" + "github.com/MinterTeam/minter-go-node/helpers" + "github.com/MinterTeam/minter-go-node/rlp" +) + +func TestCalculateCommissionTODO(t *testing.T) { + cState := getState() + + privateKey, _ := crypto.GenerateKey() + addr := crypto.PubkeyToAddress(privateKey.PublicKey) + + coinSend := types.GetBaseCoinID() + coinCommission := createNonReserveCoin(cState) + + cState.Accounts.AddBalance(addr, coinSend, helpers.BipToPip(big.NewInt(1000000))) + cState.Accounts.AddBalance(addr, coinCommission, helpers.BipToPip(big.NewInt(1000000))) + + value := helpers.BipToPip(big.NewInt(10)) + addressTo := types.Address([20]byte{1}) + + data := SendData{ + Coin: coinSend, + To: addressTo, + Value: value, + } + + encodedData, err := rlp.EncodeToBytes(data) + if err != nil { + t.Fatal(err) + } + + tx := Transaction{ + Nonce: 1, + GasPrice: 2, + ChainID: types.CurrentChainID, + GasCoin: coinCommission, + Type: TypeSend, + Data: encodedData, + SignatureType: SigTypeSingle, + } + + if err := tx.Sign(privateKey); err != nil { + t.Fatal(err) + } + + encodedTx, err := rlp.EncodeToBytes(tx) + if err != nil { + t.Fatal(err) + } + + response := NewExecutorV250(GetDataV250).RunTx(cState, encodedTx, big.NewInt(0), 0, &sync.Map{}, 0, false) + if response.Code == 0 { + t.Fatal("Response code is 0, want error") + } + + if balance := cState.Accounts.GetBalance(addr, coinSend); balance.Cmp(helpers.BipToPip(big.NewInt(1000000))) != 0 { + t.Fatalf("Target %s balance is not correct. Expected %s, got %s", addr.String(), helpers.BipToPip(big.NewInt(1000000)), balance) + } + + if balance := cState.Accounts.GetBalance(addr, coinCommission); balance.Cmp(helpers.BipToPip(big.NewInt(1000000))) != 0 { + t.Fatalf("Target %s balance is not correct. Expected %s, got %s", addr.String(), helpers.BipToPip(big.NewInt(1000000)), balance) + } +} diff --git a/coreV2/transaction/sell_all_swap_pool_v240.go b/coreV2/transaction/sell_all_swap_pool_v240.go index 18237f1a5..9c30c5d6d 100644 --- a/coreV2/transaction/sell_all_swap_pool_v240.go +++ b/coreV2/transaction/sell_all_swap_pool_v240.go @@ -130,10 +130,10 @@ func (data SellAllSwapPoolDataV240) Run(tx *Transaction, context state.Interface } checkDuplicatePools[swapper.GetID()] = struct{}{} if isGasCommissionFromPoolSwap && swapper.GetID() == commissionPoolSwapper.GetID() { - if tx.GasCoin == coinToSell && coinToBuy.IsBaseCoin() { + if tx.commissionCoin() == coinToSell && coinToBuy.IsBaseCoin() { swapper = swapper.AddLastSwapStep(commission, commissionInBaseCoin) } - if tx.GasCoin == coinToBuy && coinToSell.IsBaseCoin() { + if tx.commissionCoin() == coinToBuy && coinToSell.IsBaseCoin() { swapper = swapper.AddLastSwapStep(big.NewInt(0).Neg(commissionInBaseCoin), big.NewInt(0).Neg(commission)) } } diff --git a/coreV2/transaction/vote_commission_v250.go b/coreV2/transaction/vote_commission_v250.go index a70992fab..0d32d9db4 100644 --- a/coreV2/transaction/vote_commission_v250.go +++ b/coreV2/transaction/vote_commission_v250.go @@ -59,10 +59,31 @@ type VoteCommissionDataV250 struct { BurnToken *big.Int VoteCommission *big.Int VoteUpdate *big.Int - FailedTX *big.Int - AddLimitOrder *big.Int - RemoveLimitOrder *big.Int - More []*big.Int `rlp:"tail"` + // FailedTX *big.Int + // AddLimitOrder *big.Int + // RemoveLimitOrder *big.Int + More []*big.Int `rlp:"tail"` +} + +func (data *VoteCommissionDataV250) FailedTxPrice() *big.Int { + if len(data.More) > 0 { + return data.More[0] + } + return big.NewInt(0) +} + +func (data *VoteCommissionDataV250) AddLimitOrderPrice() *big.Int { + if len(data.More) > 1 { + return data.More[1] + } + return big.NewInt(0) +} + +func (data *VoteCommissionDataV250) RemoveLimitOrderPrice() *big.Int { + if len(data.More) > 2 { + return data.More[2] + } + return big.NewInt(0) } func (data VoteCommissionDataV250) TxType() TxType { @@ -77,10 +98,10 @@ func (data VoteCommissionDataV250) GetPubKey() types.Pubkey { } func (data VoteCommissionDataV250) basicCheck(tx *Transaction, context *state.CheckState, block uint64) *Response { - if len(data.More) > 0 { // todo: mb use + if len(data.More) != 3 { return &Response{ Code: code.DecodeError, - Log: "More parameters than expected", + Log: "More or less parameters than expected", Info: EncodeError(code.NewDecodeError()), } } @@ -88,7 +109,7 @@ func (data VoteCommissionDataV250) basicCheck(tx *Transaction, context *state.Ch if data.Height < block { return &Response{ Code: code.VoteExpired, - Log: "vote is produced for the past state", + Log: "Vote is produced for the past state", Info: EncodeError(code.NewVoteExpired(strconv.Itoa(int(block)), strconv.Itoa(int(data.Height)))), } } @@ -232,6 +253,7 @@ func (data VoteCommissionDataV250) price() *commission.Price { MintToken: data.MintToken, VoteCommission: data.VoteCommission, VoteUpdate: data.VoteUpdate, - More: append([]*big.Int{data.FailedTX, data.AddLimitOrder, data.RemoveLimitOrder}, data.More...), + More: data.More, + // More: append([]*big.Int{data.FailedTX, data.AddLimitOrder, data.RemoveLimitOrder}, data.More...), } } diff --git a/coreV2/types/appstate.go b/coreV2/types/appstate.go index b4bf90b88..3cdc7d5f6 100644 --- a/coreV2/types/appstate.go +++ b/coreV2/types/appstate.go @@ -415,4 +415,6 @@ type Commission struct { VoteCommission string `json:"vote_commission"` VoteUpdate string `json:"vote_update"` FailedTx string `json:"failed_tx"` + AddLimitOrder string `json:"add_limit_order"` + RemoveLimitOrder string `json:"remove_limit_order"` } diff --git a/go.mod b/go.mod index a7d14e5bc..2814db6c9 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,15 @@ module github.com/MinterTeam/minter-go-node go 1.15 require ( - github.com/MinterTeam/node-grpc-gateway v1.2.2-0.20210608112129-9189cd68b20e + github.com/MinterTeam/node-grpc-gateway v1.4.2 github.com/btcsuite/btcd v0.21.0-beta github.com/c-bata/go-prompt v0.2.3 - github.com/cosmos/iavl v0.15.3 + github.com/cosmos/iavl v0.17.0 github.com/go-kit/kit v0.10.0 github.com/gogo/protobuf v1.3.2 - github.com/golang/protobuf v1.4.3 + github.com/golang/protobuf v1.5.2 github.com/gorilla/handlers v1.4.2 - github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.1.0 github.com/marcusolsson/tui-go v0.4.0 @@ -26,15 +26,15 @@ require ( github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca github.com/tendermint/go-amino v0.15.1 - github.com/tendermint/tendermint v0.34.10 + github.com/tendermint/tendermint v0.34.12 github.com/tendermint/tm-db v0.6.4 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 github.com/urfave/cli/v2 v2.0.0 golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a - google.golang.org/grpc v1.37.0 - google.golang.org/protobuf v1.25.0 + google.golang.org/grpc v1.40.0 + google.golang.org/protobuf v1.26.0 ) -replace github.com/tendermint/tendermint => github.com/GrKamil/tendermint v0.34.11-0.20210610100913-0adcb9b29f96 +//replace github.com/tendermint/tendermint => github.com/MinterTeam/tendermint v0.34.11-0.20210615080504-44952755291a diff --git a/go.sum b/go.sum index 3cc0879df..cd9cf036d 100644 --- a/go.sum +++ b/go.sum @@ -39,15 +39,9 @@ github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQ github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/GrKamil/tendermint v0.34.11-0.20210610094610-77e6e02dae46 h1:i0/QkQ5NPqMIblagQVbhL+I1H3+p/Ln/xFQGZ+Xpc60= -github.com/GrKamil/tendermint v0.34.11-0.20210610094610-77e6e02dae46/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= -github.com/GrKamil/tendermint v0.34.11-0.20210610100015-5d001595527a h1:DRZeRL7aVOXYl0FSE8g/8vhL/UJO7CIdJ+n9jP8E7xk= -github.com/GrKamil/tendermint v0.34.11-0.20210610100015-5d001595527a/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= -github.com/GrKamil/tendermint v0.34.11-0.20210610100913-0adcb9b29f96 h1:FuHq5+YNN6SQaKbj+TImHsO++cOLtf5/EQiMunr7bhU= -github.com/GrKamil/tendermint v0.34.11-0.20210610100913-0adcb9b29f96/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/MinterTeam/node-grpc-gateway v1.2.2-0.20210608112129-9189cd68b20e h1:g6LU8bAOMVM9EhpIziMJHQDX5uJlDp1EXgZcwAxsYV4= -github.com/MinterTeam/node-grpc-gateway v1.2.2-0.20210608112129-9189cd68b20e/go.mod h1:d4Rw0MtsZTrFNLJJWr/jcurTYcqRVITzWuGDGo7aHxM= +github.com/MinterTeam/node-grpc-gateway v1.4.2 h1:IXuSoOCv2wx7Ye9H4iJajIbbdGT+MZ4wwyUuBH2+/jo= +github.com/MinterTeam/node-grpc-gateway v1.4.2/go.mod h1:d4Rw0MtsZTrFNLJJWr/jcurTYcqRVITzWuGDGo7aHxM= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= @@ -111,10 +105,13 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/confio/ics23/go v0.6.3 h1:PuGK2V1NJWZ8sSkNDq91jgT/cahFEW9RGp4Y5jxulf0= +github.com/confio/ics23/go v0.0.0-20200817220745-f173e6211efb/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/confio/ics23/go v0.6.3/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= +github.com/confio/ics23/go v0.6.6 h1:pkOy18YxxJ/r0XFDCnrl4Bjv6h4LkBSpLS6F38mrKL8= +github.com/confio/ics23/go v0.6.6/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -127,8 +124,11 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= -github.com/cosmos/iavl v0.15.3 h1:xE9r6HW8GeKeoYJN4zefpljZ1oukVScP/7M8oj6SUts= +github.com/cosmos/iavl v0.15.0-rc3.0.20201009144442-230e9bdf52cd/go.mod h1:3xOIaNNX19p0QrX0VqWa6voPRoJRGGYtny+DH8NEPvE= +github.com/cosmos/iavl v0.15.0-rc5/go.mod h1:WqoPL9yPTQ85QBMT45OOUzPxG/U/JcJoN7uMjgxke/I= github.com/cosmos/iavl v0.15.3/go.mod h1:OLjQiAQ4fGD2KDZooyJG9yz+p2ao2IAYSbke8mVvSA4= +github.com/cosmos/iavl v0.17.0 h1:hLZ2tfYK7Z5CaBdnq3w7maGcZg5Ut7f/lnCEjtopI+E= +github.com/cosmos/iavl v0.17.0/go.mod h1:bopHqfvADWWa2ngnLBVS79NeHV8qiNjTA2EK61bdbGs= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -140,6 +140,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/dgraph-io/badger/v2 v2.2007.1/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= @@ -162,6 +163,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -232,8 +234,10 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -247,8 +251,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -277,17 +282,21 @@ github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.1/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.14.7/go.mod h1:oYZKL012gGh6LMyg/xA7Q2yq6j8bu0wa+9w14EEthWU= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.1.0 h1:EhTvIsn53GrBLl45YVHk25cUHQHwlJfq2y8b7W5IpVY= @@ -355,7 +364,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= @@ -418,6 +426,8 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -511,6 +521,7 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -537,6 +548,7 @@ github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= @@ -546,6 +558,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= @@ -570,6 +583,12 @@ github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzH github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ= github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tendermint/tendermint v0.34.0-rc4/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxmPUrT4hNuOQWX9XUwB4= +github.com/tendermint/tendermint v0.34.0-rc6/go.mod h1:ugzyZO5foutZImv0Iyx/gOFCX6mjJTgbLHTwi17VDVg= +github.com/tendermint/tendermint v0.34.0/go.mod h1:Aj3PIipBFSNO21r+Lq3TtzQ+uKESxkbA3yo/INM4QwQ= +github.com/tendermint/tendermint v0.34.12 h1:m+kUYNhONedhJfHmHG8lqsdZvbR5t6vmhaok1yXjpKg= +github.com/tendermint/tendermint v0.34.12/go.mod h1:aeHL7alPh4uTBIJQ8mgFEE8VwJLXI1VD3rVOmH2Mcy0= +github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs+yAcLvGI= github.com/tendermint/tm-db v0.6.3/go.mod h1:lfA1dL9/Y/Y8wwyPp2NMLyn5P5Ptr/gvDFNWtrCWSf8= github.com/tendermint/tm-db v0.6.4 h1:3N2jlnYQkXNQclQwd/eKV/NzlqPlfK21cpRRIx80XXQ= github.com/tendermint/tm-db v0.6.4/go.mod h1:dptYhIpJ2M5kUuenLr+Yyf3zQOv1SgBZcl8/BmWlMBw= @@ -577,6 +596,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= @@ -601,6 +621,7 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -622,6 +643,8 @@ golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 h1:phUcVbl53swtrUN8kQEXFhUxPlIlWyBfKmidCu7P95o= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -670,12 +693,14 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -889,6 +914,7 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201111145450-ac7456db90a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201119123407-9b1e624d6bc4/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210106152847-07624b53cd92 h1:jOTk2Z6KYaWoptUFqZ167cS8peoUPjFEXrsqfVkkCGc= google.golang.org/genproto v0.0.0-20210106152847-07624b53cd92/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -910,12 +936,16 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -926,15 +956,19 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 h1:FVCohIoYO7IJoDDVpV2pdq7SgrMH6wHnuTyrdrxJNoY= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/helpers/helpers.go b/helpers/helpers.go index a704479fe..95d2179f5 100644 --- a/helpers/helpers.go +++ b/helpers/helpers.go @@ -34,6 +34,15 @@ func StringToBigInt(s string) *big.Int { return result } +func StringToBigIntOrNil(s string) *big.Int { + result, err := stringToBigInt(s) + if err != nil { + return nil + } + + return result +} + func stringToBigInt(s string) (*big.Int, error) { if s == "" { return nil, errors.New("string is empty") diff --git a/tests/example/counter/counter.go b/tests/example/counter/counter.go new file mode 100644 index 000000000..54d001a93 --- /dev/null +++ b/tests/example/counter/counter.go @@ -0,0 +1,108 @@ +package counter + +import ( + "encoding/binary" + "fmt" + "github.com/MinterTeam/minter-go-node/coreV2/transaction" + + "github.com/tendermint/tendermint/abci/example/code" + "github.com/tendermint/tendermint/abci/types" +) + +type Application struct { + types.BaseApplication + + hashCount int + TxCount int + serial bool + + txDecoder transaction.DecoderTx +} + +func NewApplication(serial bool, decoder transaction.DecoderTx) *Application { + return &Application{serial: serial, txDecoder: decoder} +} + +func (app *Application) Info(req types.RequestInfo) types.ResponseInfo { + return types.ResponseInfo{Data: fmt.Sprintf("{\"hashes\":%v,\"txs\":%v}", app.hashCount, app.TxCount)} +} + +func (app *Application) SetOption(req types.RequestSetOption) types.ResponseSetOption { + key, value := req.Key, req.Value + if key == "serial" && value == "on" { + app.serial = true + } else { + /* + TODO Panic and have the ABCI server pass an exception. + The client can call SetOptionSync() and get an `error`. + return types.ResponseSetOption{ + Error: fmt.Sprintf("Unknown key (%s) or value (%s)", key, value), + } + */ + return types.ResponseSetOption{} + } + + return types.ResponseSetOption{} +} + +func (app *Application) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx { + if app.serial { + if len(req.Tx) > 2500 { + return types.ResponseDeliverTx{ + Code: code.CodeTypeEncodingError, + Log: fmt.Sprintf("Max tx size is 2500 bytes, got %d", len(req.Tx))} + } + + if app.txDecoder != nil { + tx, _ := app.txDecoder.DecodeFromBytes(req.Tx) + if tx.Nonce != uint64(app.TxCount) { + return types.ResponseDeliverTx{ + Code: code.CodeTypeBadNonce, + Log: fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.TxCount, tx.Nonce)} + } + } + } + app.TxCount++ + return types.ResponseDeliverTx{Code: code.CodeTypeOK} +} + +func (app *Application) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx { + if app.serial { + if len(req.Tx) > 2500 { + return types.ResponseCheckTx{ + Code: code.CodeTypeEncodingError, + Log: fmt.Sprintf("Max tx size is 2500 bytes, got %d", len(req.Tx))} + } + + if app.txDecoder != nil { + tx, _ := app.txDecoder.DecodeFromBytes(req.Tx) + if tx.Nonce != uint64(app.TxCount) { + return types.ResponseCheckTx{ + Code: code.CodeTypeBadNonce, + Log: fmt.Sprintf("Invalid nonce. Expected >= %v, got %v", app.TxCount, tx.Nonce)} + } + } + } + return types.ResponseCheckTx{Code: code.CodeTypeOK} +} + +func (app *Application) Commit() (resp types.ResponseCommit) { + app.hashCount++ + if app.TxCount == 0 { + return types.ResponseCommit{} + } + hash := make([]byte, 8) + binary.BigEndian.PutUint64(hash, uint64(app.TxCount)) + return types.ResponseCommit{Data: hash} +} + +func (app *Application) Query(reqQuery types.RequestQuery) types.ResponseQuery { + switch reqQuery.Path { + case "hash": + return types.ResponseQuery{Value: []byte(fmt.Sprintf("%v", app.hashCount))} + case "tx": + return types.ResponseQuery{Value: []byte(fmt.Sprintf("%v", app.TxCount))} + default: + return types.ResponseQuery{Log: fmt.Sprintf("Invalid query path. Expected hash or tx, got %v", reqQuery.Path)} + } +} diff --git a/tests/failed_test.go b/tests/failed_test.go new file mode 100644 index 000000000..efeced409 --- /dev/null +++ b/tests/failed_test.go @@ -0,0 +1,1430 @@ +package tests + +import ( + "math/big" + "testing" + + "github.com/MinterTeam/minter-go-node/coreV2/transaction" + "github.com/MinterTeam/minter-go-node/coreV2/types" + "github.com/MinterTeam/minter-go-node/helpers" +) + +func TestFailedTxPayCommission(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "100", + Crr: 0, + Reserve: "0", + MaxSupply: "100", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "50", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "1", + }, + { + Coin: 1, + Value: "50", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(1)) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 107 { + t.Fatalf("Response code is not error: %s, %d, %s", response.Log, response.Code, response.Info) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + // check commission balance + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "49" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "49", balance) + } + } + + // check pool reserves + { + reward := app.GetCurrentRewards() + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 1).Reserves() + if reward.Sign() != 1 || r1.String() != "51" || big.NewInt(0).Add(reward, r0).Cmp(reserve0) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s and reward %s", "51", r0, r1, reward) + } + } + +} + +func TestFailedTxPayCommission_customPriceCoin(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "1", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(1)) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 107 { + t.Fatalf("Response code is not error: %s, %d", response.Log, response.Code) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + // check commission balance + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "6000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "49", balance) + } + } + + // check pool reserves + { + reward := app.GetCurrentRewards() + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 1).Reserves() + if reward.Sign() != 1 || r1.String() != "6345678901234567890" || big.NewInt(0).Add(reward, r0).Cmp(reserve0) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s and reward %s", "51", r0, r1, reward) + } + } + +} + +func TestFailedTxPayCommission_customPriceCoinAndPayBaseCoin_lessAvailable(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "10000000000000000000", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: 2, + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(0)) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 102 { + t.Fatalf("Response code is not error: %s, %d", response.Log, response.Code) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + // check commission balance + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check pool reserves + { + reward := app.GetCurrentRewards() + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 1).Reserves() + if reward.String() != "10000000000000000000" || r1.String() != "2345678901234567890" { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s and reward %s", "5000000000000000000000000000000000000", r0, r1, reward) + } + } + +} + +func TestFailedTxPayCommission_customPriceCoinAndPayBaseCoin_lessAvailable_withGasPrice(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "10000000000000000000", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: 2, + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(0), 50) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 102 { + t.Fatalf("Response code is not error: %s, %d", response.Log, response.Code) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + // check commission balance + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check pool reserves + { + reward := app.GetCurrentRewards() + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 1).Reserves() + if reward.String() != "10000000000000000000" || r1.String() != "2345678901234567890" { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s and reward %s", "5000000000000000000000000000000000000", r0, r1, reward) + } + } + +} + +func TestFailedTxPayCommission_customPriceCoinAndPayBaseCoin_withGasPrice(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "10000000000000000000000000000000000000", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: 2, + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(0), 50) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 102 { + t.Fatalf("Response code is not error: %s, %d", response.Log, response.Code) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(helpers.StringToBigInt("5058076976788935588754051349077150287")) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + // check commission balance + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check pool reserves + { + reward := app.GetCurrentRewards() + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 1).Reserves() + if reward.String() != "4941923023211064411245948650922849713" || r1.String() != "2345678901234567890" { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s and reward %s", "5000000000000000000000000000000000000", r0, r1, reward) + } + } +} + +func TestFailedTxPayCommission_customPriceCoinAndPayBaseCoin(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "10000000000000000000000000000000000000", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: 2, + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(0), 1) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 102 { + t.Fatalf("Response code is not error: %s, %d", response.Log, response.Code) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(helpers.StringToBigInt("6850582001541316700832722827411023323")) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + // check commission balance + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check pool reserves + { + reward := app.GetCurrentRewards() + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 1).Reserves() + if reward.String() != "3149417998458683299167277172588976677" || r1.String() != "2345678901234567890" { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s and reward %s", "5000000000000000000000000000000000000", r0, r1, reward) + } + } +} + +func TestFailedTxPayCommission_customPriceCoinAndCustomCommissionToken(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }, types.Coin{ + ID: 2, + Name: "bbb", + Symbol: types.StrToCoinBaseSymbol("BBB"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }, types.Pool{ + Coin0: 0, + Coin1: 2, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 2, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "1", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + { + Coin: 2, + Value: "10000000000000000000", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(2)) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 107 { + t.Fatalf("Response code is not error: %s, %d, %s", response.Log, response.Code, response.Info) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check commission balance + { + balance := app.CurrentState().Accounts().GetBalance(address, 2) + if balance.String() != "6000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "6000000000000000000", balance) + } + } + + // check pool reserves + { + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 1).Reserves() + if r0.String() != "5000000000000000000000000000000000000" || r1.String() != "2345678901234567890" { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s", "5000000000000000000000000000000000000", r0, r1) + } + } + // check pool reserves + { + reward := app.GetCurrentRewards() + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 2).Reserves() + if reward.Sign() != 1 || r1.String() != "6345678901234567890" || big.NewInt(0).Add(reward, r0).Cmp(reserve0) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s and reward %s", "51", r0, r1, reward) + } + } + +} + +func TestFailedTxPayCommission_customPriceCoinAndCustomCommissionToken_withGasPrice(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }, types.Coin{ + ID: 2, + Name: "bbb", + Symbol: types.StrToCoinBaseSymbol("BBB"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }, types.Pool{ + Coin0: 0, + Coin1: 2, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 2, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "1", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + { + Coin: 2, + Value: "10000000000000000000", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(2), 2) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 107 { + t.Fatalf("Response code is not error: %s, %d, %s", response.Log, response.Code, response.Info) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check commission balance + { + balance := app.CurrentState().Accounts().GetBalance(address, 2) + if balance.String() != "2000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "2000000000000000000", balance) + } + } + + // check pool reserves + { + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 1).Reserves() + if r0.String() != "5000000000000000000000000000000000000" || r1.String() != "2345678901234567890" { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s", "5000000000000000000000000000000000000", r0, r1) + } + } + + // check pool reserves + { + reward := app.GetCurrentRewards() + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 2).Reserves() + if reward.Sign() != 1 || r1.String() != "10345678901234567890" || big.NewInt(0).Add(reward, r0).Cmp(reserve0) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s and reward %s", "1135407462159458011337752529693750189", r0, r1, reward) + } + } +} + +func TestFailedTxPayCommission_customPriceCoinAndCustomCommissionToken_withGasPrice_lessAvailable(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }, types.Coin{ + ID: 2, + Name: "bbb", + Symbol: types.StrToCoinBaseSymbol("BBB"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }, types.Pool{ + Coin0: 0, + Coin1: 2, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 2, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "1", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + { + Coin: 2, + Value: "10000000000000000000", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(2), 50) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 107 { + t.Fatalf("Response code is not error: %s, %d, %s", response.Log, response.Code, response.Info) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check commission balance + { + balance := app.CurrentState().Accounts().GetBalance(address, 2) + if balance.String() != "0" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "0", balance) + } + } + + // check pool reserves + { + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 1).Reserves() + if r0.String() != "5000000000000000000000000000000000000" || r1.String() != "2345678901234567890" { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s", "5000000000000000000000000000000000000", r0, r1) + } + } + + // check pool reserves + { + reward := app.GetCurrentRewards() + r0, r1 := app.CurrentState().Swap().GetSwapper(0, 2).Reserves() + if reward.Sign() != 1 || r1.String() != "12345678901234567890" || big.NewInt(0).Add(reward, r0).Cmp(reserve0) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s, %s and reward %s", "951541460730256157863947745387590710", r0, r1, reward) + } + } +} + +func TestFailedTxPayCommission_customPriceCoinAndCustomCommissionBancorReserveCoin(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }, types.Coin{ + ID: 2, + Name: "bbb", + Symbol: types.StrToCoinBaseSymbol("BBB"), + Volume: "695664472679", + Crr: 50, + Reserve: "3149417998458693299167277172588976677", + MaxSupply: "695664472679", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "1", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + { + Coin: 2, + Value: "695664472679", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(2)) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 107 { + t.Fatalf("Response code is not error: %s, %d, %s", response.Log, response.Code, response.Info) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check commission balance + { + coin := app.CurrentState().Coins().GetCoin(2) + balance := app.CurrentState().Accounts().GetBalance(address, 2) + if balance.String() != "39200" && coin.Volume().String() != "39200" { + t.Fatalf("volume or balance is not correct. Expected %s, got %s and coin volume %s", "49", balance, coin.Volume()) + } + + if coin.Reserve().Cmp(helpers.StringToBigInt("10000000000000000000000")) == -1 { + t.Fatalf("reserve is not correct. Got %s", coin.Reserve()) + } + } + +} + +func TestFailedTxPayCommission_customPriceCoinAndCustomCommissionBancorReserveCoin_withGasPrice(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }, types.Coin{ + ID: 2, + Name: "bbb", + Symbol: types.StrToCoinBaseSymbol("BBB"), + Volume: "695664472679", + Crr: 50, + Reserve: "4941923023211074411245948650922849713", + MaxSupply: "695664472679", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "1", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + { + Coin: 2, + Value: "695664472679", + }, + }, + Nonce: 0, + MultisigData: nil, + }) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(2), 50) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 107 { + t.Fatalf("Response code is not error: %s, %d, %s", response.Log, response.Code, response.Info) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check commission balance + { + coin := app.CurrentState().Coins().GetCoin(2) + balance := app.CurrentState().Accounts().GetBalance(address, 2) + if balance.String() != "31294" && coin.Volume().String() != "31294" { + t.Fatalf("volume or balance is not correct. Expected %s, got %s and coin volume %s", "31294", balance, coin.Volume()) + } + + if coin.Reserve().Cmp(helpers.StringToBigInt("10000000000000000000000")) == -1 { + t.Fatalf("reserve is not correct. Got %s", coin.Reserve()) + } + } + +} + +func TestFailedTxPayCommission_customPriceCoinAndCustomCommissionBancorReserveCoin_withGasPrice_lessAvailable(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }, types.Coin{ + ID: 2, + Name: "bbb", + Symbol: types.StrToCoinBaseSymbol("BBB"), + Volume: "695664472679", + Crr: 50, + Reserve: "4941923023211074411245948650922849713", + MaxSupply: "695664472679", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(4e18).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "1", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + { + Coin: 2, + Value: "95664472679", + }, + }, + Nonce: 0, + MultisigData: nil, + }, + types.Account{ + Address: types.Address{}, + Balance: []types.Balance{ + { + Coin: 2, + Value: "600000000000", + }, + }, + }, + ) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(2), 50) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 107 { + t.Fatalf("Response code is not error: %s, %d, %s", response.Log, response.Code, response.Info) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check commission balance + { + coin := app.CurrentState().Coins().GetCoin(2) + balance := app.CurrentState().Accounts().GetBalance(address, 2) + if balance.String() != "0" && coin.Volume().String() != "600000000000" { + t.Fatalf("volume or balance is not correct. Expected %s, got %s and coin volume %s", "0", balance, coin.Volume()) + } + + if coin.Reserve().Cmp(helpers.StringToBigInt("10000000000000000000000")) == -1 { + t.Fatalf("reserve is not correct. Got %s", coin.Reserve()) + } + } + +} + +func TestFailedTxPayCommission_customPriceCoinAndCustomCommissionBancorReserveCoin_withGasPrice_lessReserve(t *testing.T) { + address, pk := CreateAddress() // create account for test + + state := DefaultAppState() // generate default state + + state.Version = "v250" + + state.Coins = append(state.Coins, types.Coin{ + ID: 1, + Name: "aaa", + Symbol: types.StrToCoinBaseSymbol("AAA"), + Volume: "12345678901234567890", + Crr: 0, + Reserve: "0", + MaxSupply: "12345678901234567890", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }, types.Coin{ + ID: 2, + Name: "bbb", + Symbol: types.StrToCoinBaseSymbol("BBB"), + Volume: "695664472679", + Crr: 50, + Reserve: "4941923023211074411245948650922849710", + MaxSupply: "695664472679", + Version: 0, + OwnerAddress: nil, + Mintable: false, + Burnable: false, + }) + state.Commission.Coin = 1 + state.Commission.FailedTx = big.NewInt(1e15).String() + + reserve0 := helpers.BipToPip(big.NewInt(5e18)) + state.Pools = append(state.Pools, types.Pool{ + Coin0: 0, + Coin1: 1, + Reserve0: reserve0.String(), + Reserve1: "2345678901234567890", + ID: 1, + }) + state.Accounts = append(state.Accounts, types.Account{ + Address: address, + Balance: []types.Balance{ + { + Coin: uint64(types.GetBaseCoinID()), + Value: "1", + }, + { + Coin: 1, + Value: "10000000000000000000", + }, + { + Coin: 2, + Value: "95664472679", + }, + }, + Nonce: 0, + MultisigData: nil, + }, + types.Account{ + Address: types.Address{}, + Balance: []types.Balance{ + { + Coin: 2, + Value: "600000000000", + }, + }, + }, + ) + + app := CreateApp(state) // create application + SendBeginBlock(app, 1) // send BeginBlock + + recipient, _ := CreateAddress() // generate recipient + tx := CreateTx(app, address, transaction.TypeSend, transaction.SendData{ + Coin: types.GetBaseCoinID(), + To: recipient, + Value: big.NewInt(100), + }, types.CoinID(2), 50) + + response := SendTx(app, SignTx(pk, tx)) // compose and send tx + + // check that result is error + if response.Code != 107 { + t.Fatalf("Response code is not error: %s, %d, %s", response.Log, response.Code, response.Info) + } + + SendEndBlock(app, 1) // send EndBlock + SendCommit(app) // send Commit + + // check recipient's balance + { + balance := app.CurrentState().Accounts().GetBalance(address, types.GetBaseCoinID()) + if balance.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("address balance is not correct. Expected %s, got %s", big.NewInt(1), balance) + } + } + + { + balance := app.CurrentState().Accounts().GetBalance(address, 1) + if balance.String() != "10000000000000000000" { + t.Fatalf("address balance is not correct. Expected %s, got %s", "10000000000000000000", balance) + } + } + + // check commission balance + { + coin := app.CurrentState().Coins().GetCoin(2) + balance := app.CurrentState().Accounts().GetBalance(address, 2) + if balance.String() != "88294932483" && coin.Volume().String() != "688294932483" { + t.Fatalf("volume or balance is not correct. Expected %s, got %s and coin volume %s", "88294932483", balance, coin.Volume()) + } + + if coin.Reserve().Cmp(helpers.StringToBigInt("10000000000000000000000")) == -1 { + t.Fatalf("reserve is not correct. Got %s", coin.Reserve()) + } + } + +} diff --git a/tests/helpers_test.go b/tests/helpers_test.go index dc65622d8..f33a15b7f 100644 --- a/tests/helpers_test.go +++ b/tests/helpers_test.go @@ -2,6 +2,8 @@ package tests import ( "crypto/ecdsa" + "time" + "github.com/MinterTeam/minter-go-node/cmd/utils" "github.com/MinterTeam/minter-go-node/config" "github.com/MinterTeam/minter-go-node/coreV2/minter" @@ -13,7 +15,6 @@ import ( tmTypes "github.com/tendermint/tendermint/abci/types" tmTypes1 "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/proto/tendermint/version" - "time" ) // CreateApp creates and returns new Blockchain instance @@ -95,18 +96,23 @@ func SendEndBlock(app *minter.Blockchain, height int64) tmTypes.ResponseEndBlock // CreateTx composes and returns Tx with given params. // Nonce, chain id, gas price, gas coin and signature type fields are auto-filled. -func CreateTx(app *minter.Blockchain, address types.Address, txType transaction.TxType, data interface{}) transaction.Transaction { +func CreateTx(app *minter.Blockchain, address types.Address, txType transaction.TxType, data interface{}, gas types.CoinID, gasPrice ...uint32) transaction.Transaction { nonce := app.CurrentState().Accounts().GetNonce(address) + 1 bData, err := rlp.EncodeToBytes(data) if err != nil { panic(err) } + var mulGas uint32 = 1 + if len(gasPrice) != 0 { + mulGas = gasPrice[0] + } + tx := transaction.Transaction{ Nonce: nonce, ChainID: types.CurrentChainID, - GasPrice: 1, - GasCoin: types.GetBaseCoinID(), + GasPrice: mulGas, + GasCoin: gas, Type: txType, Data: bData, SignatureType: transaction.SigTypeSingle, @@ -144,6 +150,7 @@ func CreateAddress() (types.Address, *ecdsa.PrivateKey) { // DefaultAppState returns new AppState with some predefined values func DefaultAppState() types.AppState { return types.AppState{ + Version: "v250", Note: "", Validators: nil, Candidates: nil, @@ -194,10 +201,13 @@ func DefaultAppState() types.AppState { AddLiquidity: "100000000000000000", RemoveLiquidity: "100000000000000000", EditCandidateCommission: "10000000000000000000", - BurnToken: "100000000000000000", MintToken: "100000000000000000", + BurnToken: "100000000000000000", VoteCommission: "1000000000000000000", VoteUpdate: "1000000000000000000", + FailedTx: "", + AddLimitOrder: "", + RemoveLimitOrder: "", }, CommissionVotes: nil, UpdateVotes: nil, diff --git a/tests/send_test.go b/tests/send_test.go index 69990de08..602912791 100644 --- a/tests/send_test.go +++ b/tests/send_test.go @@ -1,12 +1,13 @@ package tests import ( + "math/big" + "testing" + "github.com/MinterTeam/minter-go-node/coreV2/code" "github.com/MinterTeam/minter-go-node/coreV2/transaction" "github.com/MinterTeam/minter-go-node/coreV2/types" "github.com/MinterTeam/minter-go-node/helpers" - "math/big" - "testing" ) func TestSend(t *testing.T) { @@ -37,7 +38,7 @@ func TestSend(t *testing.T) { Coin: types.GetBaseCoinID(), To: recipient, Value: value, - }) + }, 0) response := SendTx(app, SignTx(pk, tx)) // compose and send tx diff --git a/tests/votes_test.go b/tests/votes_test.go index ca0249bc0..ac3d91e21 100644 --- a/tests/votes_test.go +++ b/tests/votes_test.go @@ -26,7 +26,7 @@ func TestVoteupdate(t *testing.T) { address6 := crypto.PubkeyToAddress(privateKey6.PublicKey) state := DefaultAppState() // generate default state - + state.Version = "v230" // add address to genesis state state.Accounts = append(state.Accounts, types.Account{ @@ -259,7 +259,7 @@ func TestVoteupdate(t *testing.T) { PubKey: types.Pubkey{1}, Height: 2, Version: "a", - }) + }, 0) response := SendTx(app, SignTx(privateKey1, tx)) // compose and send tx @@ -273,7 +273,7 @@ func TestVoteupdate(t *testing.T) { PubKey: types.Pubkey{2}, Height: 2, Version: "a", - }) + }, 0) response := SendTx(app, SignTx(privateKey2, tx)) // compose and send tx @@ -287,7 +287,7 @@ func TestVoteupdate(t *testing.T) { PubKey: types.Pubkey{3}, Height: 2, Version: "a", - }) + }, 0) response := SendTx(app, SignTx(privateKey3, tx)) // compose and send tx @@ -301,7 +301,7 @@ func TestVoteupdate(t *testing.T) { PubKey: types.Pubkey{4}, Height: 2, Version: "a", - }) + }, 0) response := SendTx(app, SignTx(privateKey4, tx)) // compose and send tx @@ -315,7 +315,7 @@ func TestVoteupdate(t *testing.T) { PubKey: types.Pubkey{5}, Height: 2, Version: "aA", - }) + }, 0) response := SendTx(app, SignTx(privateKey5, tx)) // compose and send tx @@ -331,11 +331,12 @@ func TestVoteupdate(t *testing.T) { SendEndBlock(app, 2) // send EndBlock SendCommit(app) // send Commit - if len(app.UpdateVersions()) != 1 { - t.Fatalf("not updates") + currentVersion := "" + for _, version := range app.UpdateVersions() { + currentVersion = version.Name } - if app.UpdateVersions()[0].Name != "a" { + if currentVersion != "a" { t.Fatalf("error update") } } @@ -355,7 +356,7 @@ func TestVoteCommissionFail(t *testing.T) { address6 := crypto.PubkeyToAddress(privateKey6.PublicKey) state := DefaultAppState() // generate default state - + state.Version = "v230" // add address to genesis state state.Accounts = append(state.Accounts, types.Account{ @@ -597,7 +598,7 @@ func TestVoteCommissionFail(t *testing.T) { Coin: types.GetBaseCoinID(), Height: 5, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey1, tx)) // compose and send tx @@ -612,7 +613,7 @@ func TestVoteCommissionFail(t *testing.T) { Coin: types.GetBaseCoinID(), Height: 5, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey2, tx)) // compose and send tx @@ -627,7 +628,7 @@ func TestVoteCommissionFail(t *testing.T) { Coin: types.GetBaseCoinID(), Height: 5, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey3, tx)) // compose and send tx @@ -647,7 +648,7 @@ func TestVoteCommissionFail(t *testing.T) { Coin: types.GetBaseCoinID(), Height: 5, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey5, tx)) // compose and send tx @@ -662,7 +663,7 @@ func TestVoteCommissionFail(t *testing.T) { Coin: types.GetBaseCoinID(), Height: 5, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey6, tx)) // compose and send tx @@ -678,7 +679,7 @@ func TestVoteCommissionFail(t *testing.T) { Coin: types.GetBaseCoinID(), Height: 5, Send: big.NewInt(2e18), // Diff - }) + }, 0) response := SendTx(app, SignTx(privateKey4, tx)) // compose and send tx @@ -715,7 +716,7 @@ func TestVoteCommissionOKUpdateVersion(t *testing.T) { address6 := crypto.PubkeyToAddress(privateKey6.PublicKey) state := DefaultAppState() // generate default state - + state.Version = "v230" // add address to genesis state state.Accounts = append(state.Accounts, types.Account{ @@ -960,7 +961,7 @@ func TestVoteCommissionOKUpdateVersion(t *testing.T) { Coin: types.GetBaseCoinID(), Height: haltBlockV210 + 4, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey1, tx)) // compose and send tx @@ -975,7 +976,7 @@ func TestVoteCommissionOKUpdateVersion(t *testing.T) { Coin: types.GetBaseCoinID(), Height: haltBlockV210 + 4, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey2, tx)) // compose and send tx @@ -990,7 +991,7 @@ func TestVoteCommissionOKUpdateVersion(t *testing.T) { Coin: types.GetBaseCoinID(), Height: haltBlockV210 + 4, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey3, tx)) // compose and send tx @@ -1010,7 +1011,7 @@ func TestVoteCommissionOKUpdateVersion(t *testing.T) { Coin: types.GetBaseCoinID(), Height: haltBlockV210 + 4, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey5, tx)) // compose and send tx @@ -1025,7 +1026,7 @@ func TestVoteCommissionOKUpdateVersion(t *testing.T) { Coin: types.GetBaseCoinID(), Height: haltBlockV210 + 4, Send: big.NewInt(9999), - }) + }, 0) response := SendTx(app, SignTx(privateKey6, tx)) // compose and send tx @@ -1041,7 +1042,7 @@ func TestVoteCommissionOKUpdateVersion(t *testing.T) { Coin: types.GetBaseCoinID(), Height: haltBlockV210 + 4, Send: big.NewInt(2e18), // Diff - }) + }, 0) response := SendTx(app, SignTx(privateKey4, tx)) // compose and send tx diff --git a/version/version.go b/version/version.go index 682cec9cb..385eb4f7f 100755 --- a/version/version.go +++ b/version/version.go @@ -7,7 +7,7 @@ const ( var ( // Version must be a string because scripts like dist.sh read this file. - Version = "2.4.1" + Version = "2.5.0" // GitCommit is the current HEAD set using ldflags. GitCommit string