From f902592a4d1c4d03ec0835fc9198aa3130874ff1 Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 00:55:32 -0700 Subject: [PATCH 01/20] [r3 patch] throttle transactions with configuration per-network level --- cmd/client/wallet/main.go | 2 +- internal/configs/sharding/fixedschedule.go | 24 ++++++ internal/configs/sharding/localnet.go | 29 ++++++- internal/configs/sharding/mainnet.go | 28 +++++++ internal/configs/sharding/shardingconfig.go | 46 +++++++++++ internal/configs/sharding/testnet.go | 27 +++++++ node/node.go | 15 ++-- node/node_handler.go | 4 +- node/node_handler_test.go | 4 +- node/node_newblock.go | 2 +- node/staking_test.go | 2 +- node/worker/worker.go | 87 +++++++++++++++++++-- 12 files changed, 250 insertions(+), 20 deletions(-) diff --git a/cmd/client/wallet/main.go b/cmd/client/wallet/main.go index 3c86ffd2f..0cae37f95 100644 --- a/cmd/client/wallet/main.go +++ b/cmd/client/wallet/main.go @@ -896,7 +896,7 @@ func submitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uin fmt.Printf("Error in SubmitTransaction: %v\n", err) return err } - fmt.Printf("Transaction Id for shard %d: %s\n", int(shardID), tx.Hash().Hex()) + fmt.Printf("Transaction Id for shard %d submitted: %s\n", int(shardID), tx.Hash().Hex()) // FIXME (leo): how to we know the tx was successful sent to the network // this is a hacky way to wait for sometime time.Sleep(3 * time.Second) diff --git a/internal/configs/sharding/fixedschedule.go b/internal/configs/sharding/fixedschedule.go index 96ff0ecf0..8f2b8d198 100644 --- a/internal/configs/sharding/fixedschedule.go +++ b/internal/configs/sharding/fixedschedule.go @@ -2,6 +2,8 @@ package shardingconfig import ( "math/big" + + "github.com/harmony-one/harmony/common/denominations" ) const ( @@ -32,6 +34,28 @@ func (s fixedSchedule) IsLastBlock(blockNum uint64) bool { return blockNum%blocks == blocks-1 } +func (s fixedSchedule) MaxTxAmountLimit() *big.Int { + amountBigInt := big.NewInt(int64(mainnetMaxTxAmountLimit * denominations.Nano)) + amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) + return amountBigInt +} + +func (s fixedSchedule) MaxTxsPerAccountInBlockLimit() uint64 { + return mainnetMaxTxsPerAccountInBlockLimit +} + +func (s fixedSchedule) MaxTxsPerBlockLimit() int { + return mainnetMaxTxsPerBlockLimit +} + +func (s fixedSchedule) TxsThrottleConfig() *TxsThrottleConfig { + return &TxsThrottleConfig{ + MaxTxAmountLimit: s.MaxTxAmountLimit(), + MaxTxsPerAccountInBlockLimit: s.MaxTxsPerAccountInBlockLimit(), + MaxTxsPerBlockLimit: s.MaxTxsPerBlockLimit(), + } +} + // NewFixedSchedule returns a sharding configuration schedule that uses the // given config instance for all epochs. Useful for testing. func NewFixedSchedule(instance Instance) Schedule { diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index 1c853885a..a47562cce 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -3,6 +3,7 @@ package shardingconfig import ( "math/big" + "github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/internal/genesis" ) @@ -18,6 +19,10 @@ const ( localnetEpochBlock1 = 20 twoOne = 5 + + localnetMaxTxAmountLimit = 1e2 // unit is in One + localnetMaxTxsPerAccountInBlockLimit = 2 + localnetMaxTxsPerBlockLimit = 8000 ) func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -31,7 +36,7 @@ func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { } } -func (localnetSchedule) BlocksPerEpoch() uint64 { +func (ls localnetSchedule) BlocksPerEpoch() uint64 { return twoOne } @@ -57,6 +62,28 @@ func (ls localnetSchedule) IsLastBlock(blockNum uint64) bool { } } +func (ls localnetSchedule) MaxTxAmountLimit() *big.Int { + amountBigInt := big.NewInt(int64(localnetMaxTxAmountLimit * denominations.Nano)) + amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) + return amountBigInt +} + +func (ls localnetSchedule) MaxTxsPerAccountInBlockLimit() uint64 { + return localnetMaxTxsPerAccountInBlockLimit +} + +func (ls localnetSchedule) MaxTxsPerBlockLimit() int { + return localnetMaxTxsPerBlockLimit +} + +func (ls localnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { + return &TxsThrottleConfig{ + MaxTxAmountLimit: ls.MaxTxAmountLimit(), + MaxTxsPerAccountInBlockLimit: ls.MaxTxsPerAccountInBlockLimit(), + MaxTxsPerBlockLimit: ls.MaxTxsPerBlockLimit(), + } +} + var localnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(localnetV1Epoch), big.NewInt(localnetV2Epoch)} var localnetV0 = MustNewInstance(2, 7, 5, genesis.LocalHarmonyAccounts, genesis.LocalFnAccounts, localnetReshardingEpoch) diff --git a/internal/configs/sharding/mainnet.go b/internal/configs/sharding/mainnet.go index 5dc077556..b35252234 100644 --- a/internal/configs/sharding/mainnet.go +++ b/internal/configs/sharding/mainnet.go @@ -3,6 +3,7 @@ package shardingconfig import ( "math/big" + "github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/internal/genesis" ) @@ -11,6 +12,10 @@ const ( blocksPerShard = 16384 // 2^14 mainnetV1Epoch = 1 mainnetV2Epoch = 5 + + mainnetMaxTxAmountLimit = 1e3 // unit is in One + mainnetMaxTxsPerAccountInBlockLimit = 10 + mainnetMaxTxsPerBlockLimit = 8000 ) // MainnetSchedule is the mainnet sharding configuration schedule. @@ -57,7 +62,30 @@ func (ms mainnetSchedule) IsLastBlock(blockNum uint64) bool { } } +func (ms mainnetSchedule) MaxTxAmountLimit() *big.Int { + amountBigInt := big.NewInt(int64(mainnetMaxTxAmountLimit * denominations.Nano)) + amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) + return amountBigInt +} + +func (ms mainnetSchedule) MaxTxsPerAccountInBlockLimit() uint64 { + return mainnetMaxTxsPerAccountInBlockLimit +} + +func (ms mainnetSchedule) MaxTxsPerBlockLimit() int { + return mainnetMaxTxsPerBlockLimit +} + +func (ms mainnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { + return &TxsThrottleConfig{ + MaxTxAmountLimit: ms.MaxTxAmountLimit(), + MaxTxsPerAccountInBlockLimit: ms.MaxTxsPerAccountInBlockLimit(), + MaxTxsPerBlockLimit: ms.MaxTxsPerBlockLimit(), + } +} + var mainnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(mainnetV1Epoch), big.NewInt(mainnetV2Epoch)} + var mainnetV0 = MustNewInstance(4, 150, 112, genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, mainnetReshardingEpoch) var mainnetV1 = MustNewInstance(4, 152, 112, genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1, mainnetReshardingEpoch) var mainnetV2 = MustNewInstance(4, 200, 148, genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV2, mainnetReshardingEpoch) diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index e556366fb..060fa07c5 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -21,6 +21,18 @@ type Schedule interface { // IsLastBlock check if the block is the last block in the epoch IsLastBlock(blockNum uint64) bool + + // Max amount limit for a valid transaction + MaxTxAmountLimit() *big.Int + + // Max number of transactions of a particular account per block level + MaxTxsPerAccountInBlockLimit() uint64 + + // Max total number of transactions in a block + MaxTxsPerBlockLimit() int + + // configuration for throttling pending transactions + TxsThrottleConfig() *TxsThrottleConfig } // Instance is one sharding configuration instance. @@ -47,3 +59,37 @@ type Instance interface { // ReshardingEpoch returns a list of Epoch while off-chain resharding happens ReshardingEpoch() []*big.Int } + +// TxThrottleFlag indicates the throttling flag for a particular transaction +type TxThrottleFlag int + +// Enum for different TxThrottleFlag +const ( + Select TxThrottleFlag = iota + Unselect + Invalid +) + +func (result TxThrottleFlag) String() string { + switch result { + case Select: + return "Select" + case Unselect: + return "Unselect" + case Invalid: + return "Invalid" + } + return "Unknown" +} + +// TxsThrottleConfig contains configuration for throttling pending transactions per node block +type TxsThrottleConfig struct { + // Max amount limit for a valid transaction + MaxTxAmountLimit *big.Int + + // Max number of transactions of a particular account per block level + MaxTxsPerAccountInBlockLimit uint64 + + // Max total number of transactions in a block + MaxTxsPerBlockLimit int +} diff --git a/internal/configs/sharding/testnet.go b/internal/configs/sharding/testnet.go index c30027122..de8710c44 100644 --- a/internal/configs/sharding/testnet.go +++ b/internal/configs/sharding/testnet.go @@ -3,6 +3,7 @@ package shardingconfig import ( "math/big" + "github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/internal/genesis" ) @@ -18,6 +19,10 @@ const ( testnetEpochBlock1 = 78 threeOne = 111 + + testnetMaxTxAmountLimit = 1e3 // unit is in One + testnetMaxTxsPerAccountInBlockLimit = 10 + testnetMaxTxsPerBlockLimit = 8000 ) func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -58,6 +63,28 @@ func (ts testnetSchedule) IsLastBlock(blockNum uint64) bool { } } +func (ts testnetSchedule) MaxTxAmountLimit() *big.Int { + amountBigInt := big.NewInt(int64(testnetMaxTxAmountLimit * denominations.Nano)) + amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) + return amountBigInt +} + +func (ts testnetSchedule) MaxTxsPerAccountInBlockLimit() uint64 { + return testnetMaxTxsPerAccountInBlockLimit +} + +func (ts testnetSchedule) MaxTxsPerBlockLimit() int { + return testnetMaxTxsPerBlockLimit +} + +func (ts testnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { + return &TxsThrottleConfig{ + MaxTxAmountLimit: ts.MaxTxAmountLimit(), + MaxTxsPerAccountInBlockLimit: ts.MaxTxsPerAccountInBlockLimit(), + MaxTxsPerBlockLimit: ts.MaxTxsPerBlockLimit(), + } +} + var testnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(testnetV1Epoch), big.NewInt(testnetV2Epoch)} var testnetV0 = MustNewInstance(2, 150, 150, genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch) diff --git a/node/node.go b/node/node.go index 223645385..dc3016527 100644 --- a/node/node.go +++ b/node/node.go @@ -225,10 +225,11 @@ func (node *Node) Beaconchain() *core.BlockChain { } func (node *Node) reducePendingTransactions() { + txPoolLimit := core.ShardingSchedule.MaxTxsPerBlockLimit() // If length of pendingTransactions is greater than TxPoolLimit then by greedy take the TxPoolLimit recent transactions. - if len(node.pendingTransactions) > TxPoolLimit+TxPoolLimit { + if len(node.pendingTransactions) > txPoolLimit+txPoolLimit { curLen := len(node.pendingTransactions) - node.pendingTransactions = append(types.Transactions(nil), node.pendingTransactions[curLen-TxPoolLimit:]...) + node.pendingTransactions = append(types.Transactions(nil), node.pendingTransactions[curLen-txPoolLimit:]...) utils.GetLogger().Info("mem stat reduce pending transaction") } } @@ -254,16 +255,20 @@ func (node *Node) AddPendingTransaction(newTx *types.Transaction) { // Take out a subset of valid transactions from the pending transaction list // Note the pending transaction list will then contain the rest of the txs -func (node *Node) getTransactionsForNewBlock(maxNumTxs int, coinbase common.Address) types.Transactions { +func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Transactions { if node.NodeConfig.GetNetworkType() == nodeconfig.Mainnet { return types.Transactions{} } node.pendingTxMutex.Lock() - selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(node.pendingTransactions, maxNumTxs, coinbase) + selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(node.pendingTransactions, core.ShardingSchedule.TxsThrottleConfig(), coinbase) node.pendingTransactions = unselected node.reducePendingTransactions() - utils.GetLogInstance().Debug("Selecting Transactions", "remainPending", len(node.pendingTransactions), "selected", len(selected), "invalidDiscarded", len(invalid)) + utils.Logger().Info(). + Int("remainPending", len(node.pendingTransactions)). + Int("selected", len(selected)). + Int("invalidDiscarded", len(invalid)). + Msg("Selecting Transactions") node.pendingTxMutex.Unlock() return selected } diff --git a/node/node_handler.go b/node/node_handler.go index 6db7e1e15..754c5a6d8 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -40,9 +40,7 @@ import ( ) const ( - // MaxNumberOfTransactionsPerBlock is the max number of transaction per a block. - MaxNumberOfTransactionsPerBlock = 8000 - consensusTimeout = 30 * time.Second + consensusTimeout = 30 * time.Second ) // ReceiveGlobalMessage use libp2p pubsub mechanism to receive global broadcast messages diff --git a/node/node_handler_test.go b/node/node_handler_test.go index e5d259aa6..b2f6bb7b8 100644 --- a/node/node_handler_test.go +++ b/node/node_handler_test.go @@ -30,7 +30,7 @@ func TestAddNewBlock(t *testing.T) { nodeconfig.GetShardConfig(0).SetNetworkType(nodeconfig.Devnet) node := New(host, consensus, testDBFactory, false) - selectedTxs := node.getTransactionsForNewBlock(MaxNumberOfTransactionsPerBlock, common.Address{}) + selectedTxs := node.getTransactionsForNewBlock(common.Address{}) node.Worker.CommitTransactions(selectedTxs, common.Address{}) block, _ := node.Worker.Commit([]byte{}, []byte{}, 0, common.Address{}) @@ -59,7 +59,7 @@ func TestVerifyNewBlock(t *testing.T) { } node := New(host, consensus, testDBFactory, false) - selectedTxs := node.getTransactionsForNewBlock(MaxNumberOfTransactionsPerBlock, common.Address{}) + selectedTxs := node.getTransactionsForNewBlock(common.Address{}) node.Worker.CommitTransactions(selectedTxs, common.Address{}) block, _ := node.Worker.Commit([]byte{}, []byte{}, 0, common.Address{}) diff --git a/node/node_newblock.go b/node/node_newblock.go index 3f7fbbd5b..451e48b8a 100644 --- a/node/node_newblock.go +++ b/node/node_newblock.go @@ -50,7 +50,7 @@ func (node *Node) WaitForConsensusReadyv2(readySignal chan struct{}, stopChan ch // Normal tx block consensus selectedTxs := types.Transactions{} // Empty transaction list if node.NodeConfig.GetNetworkType() != nodeconfig.Mainnet { - selectedTxs = node.getTransactionsForNewBlock(MaxNumberOfTransactionsPerBlock, coinbase) + selectedTxs = node.getTransactionsForNewBlock(coinbase) if err := node.Worker.UpdateCurrent(coinbase); err != nil { utils.GetLogger().Error("Failed updating worker's state", "Error", err) } diff --git a/node/staking_test.go b/node/staking_test.go index 9afbd2b8b..da3cfd094 100644 --- a/node/staking_test.go +++ b/node/staking_test.go @@ -38,7 +38,7 @@ func TestUpdateStakingList(t *testing.T) { node := New(host, consensus, testDBFactory, false) for i := 0; i < 5; i++ { - selectedTxs := node.getTransactionsForNewBlock(MaxNumberOfTransactionsPerBlock, common.Address{}) + selectedTxs := node.getTransactionsForNewBlock(common.Address{}) node.Worker.CommitTransactions(selectedTxs, common.Address{}) block, _ := node.Worker.Commit([]byte{}, []byte{}, 0, common.Address{}) diff --git a/node/worker/worker.go b/node/worker/worker.go index 5b2e995b0..50eeb6ea6 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -12,6 +12,8 @@ import ( "github.com/harmony-one/harmony/core/state" "github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/vm" + + shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding" "github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/utils" ) @@ -41,11 +43,64 @@ type Worker struct { shardID uint32 } +// Returns a tuple where the first value is the txs sender account address, +// the second is the throttling result enum for the transaction of interest. +// Throttling happens based on the amount, frequency, etc. +func (w *Worker) throttleTxs(selected types.Transactions, txsThrottleConfig *shardingconfig.TxsThrottleConfig, txnCnts map[common.Address]uint64, tx *types.Transaction) (common.Address, shardingconfig.TxThrottleFlag) { + chainID := tx.ChainID() + // Depending on the presence of the chain ID, sign with EIP155 or homestead + var s types.Signer + if chainID != nil { + s = types.NewEIP155Signer(chainID) + } else { + s = types.HomesteadSigner{} + } + + var sender common.Address + msg, err := tx.AsMessage(s) + if err != nil { + utils.Logger().Error().Msg("Error when parsing tx into message") + } else { + sender = msg.From() + } + + // already selected max num txs + if len(selected) > (*txsThrottleConfig).MaxTxsPerBlockLimit { + utils.Logger().Debug(). + Int("MaxTxsPerBlockLimit", (*txsThrottleConfig).MaxTxsPerBlockLimit). + Msg("Throttling tx with max txs per block limit") + return sender, shardingconfig.Unselect + } + + // throttle a single sender sending too many transactions in one block + if ((*txsThrottleConfig).MaxTxAmountLimit).Cmp(tx.Value()) < 0 { + utils.Logger().Debug(). + Uint64("MaxTxAmountLimit", (*txsThrottleConfig).MaxTxAmountLimit.Uint64()). + Uint64("Tx amount", tx.Value().Uint64()). + Msg("Throttling tx with max amount limit") + return sender, shardingconfig.Invalid + } + + // throttle too large transaction + if txnCnts[sender] >= (*txsThrottleConfig).MaxTxsPerAccountInBlockLimit { + utils.Logger().Debug(). + Uint64("MaxTxsPerAccountInBlockLimit", (*txsThrottleConfig).MaxTxsPerAccountInBlockLimit). + Msg("Throttling tx with max txs per account in a single block limit") + return sender, shardingconfig.Unselect + } + + return sender, shardingconfig.Select +} + // SelectTransactionsForNewBlock selects transactions for new block. -func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, maxNumTxs int, coinbase common.Address) (types.Transactions, types.Transactions, types.Transactions) { +func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, txsThrottleConfig *shardingconfig.TxsThrottleConfig, coinbase common.Address) (types.Transactions, types.Transactions, types.Transactions) { if w.current.gasPool == nil { w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) } + + // used for per account transaction frequency throttling + txnCnts := make(map[common.Address]uint64) + selected := types.Transactions{} unselected := types.Transactions{} invalid := types.Transactions{} @@ -53,17 +108,37 @@ func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, maxNumTxs if tx.ShardID() != w.shardID { invalid = append(invalid, tx) } - snap := w.current.state.Snapshot() - _, err := w.commitTransaction(tx, coinbase) - if len(selected) > maxNumTxs { + + sender, flag := w.throttleTxs(selected, txsThrottleConfig, txnCnts, tx) + switch flag { + case shardingconfig.Unselect: unselected = append(unselected, tx) - } else { + utils.Logger().Info(). + Str("Transaction Id", tx.Hash().Hex()). + Str("txThrottleFlag", flag.String()). + Msg("Transaction Throttle flag") + + case shardingconfig.Invalid: + invalid = append(invalid, tx) + utils.Logger().Info(). + Str("txThrottleFlag", flag.String()). + Str("Transaction Id", tx.Hash().Hex()). + Msg("Transaction Throttle flag") + + case shardingconfig.Select: + snap := w.current.state.Snapshot() + _, err := w.commitTransaction(tx, coinbase) if err != nil { w.current.state.RevertToSnapshot(snap) invalid = append(invalid, tx) - utils.GetLogger().Debug("Invalid transaction", "Error", err) + utils.Logger().Error(). + Err(err). + Str("Transaction Id", tx.Hash().Hex()). + Str("txThrottleFlag", flag.String()). + Msg("Transaction Throttle flag") } else { selected = append(selected, tx) + txnCnts[sender]++ } } } From af476b3ebc7269644abff68d6d48b2ab3cbb1aae Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 07:14:41 -0700 Subject: [PATCH 02/20] enable tx for all type of network (mainnet, testnet, local) --- cmd/harmony/main.go | 6 ++---- node/node.go | 21 +++++++-------------- node/node_newblock.go | 18 ++++++------------ 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/cmd/harmony/main.go b/cmd/harmony/main.go index 361970c2c..8671da91e 100644 --- a/cmd/harmony/main.go +++ b/cmd/harmony/main.go @@ -505,10 +505,8 @@ func main() { currentNode.ServiceManagerSetup() // RPC for SDK not supported for mainnet. - if *networkType != nodeconfig.Mainnet { - if err := currentNode.StartRPC(*port); err != nil { - ctxerror.Warn(utils.GetLogger(), err, "StartRPC failed") - } + if err := currentNode.StartRPC(*port); err != nil { + ctxerror.Warn(utils.GetLogger(), err, "StartRPC failed") } currentNode.RunServices() currentNode.StartServer() diff --git a/node/node.go b/node/node.go index dc3016527..45480e6a7 100644 --- a/node/node.go +++ b/node/node.go @@ -236,29 +236,22 @@ func (node *Node) reducePendingTransactions() { // Add new transactions to the pending transaction list. func (node *Node) addPendingTransactions(newTxs types.Transactions) { - if node.NodeConfig.GetNetworkType() != nodeconfig.Mainnet { - node.pendingTxMutex.Lock() - node.pendingTransactions = append(node.pendingTransactions, newTxs...) - node.reducePendingTransactions() - node.pendingTxMutex.Unlock() - utils.GetLogInstance().Info("Got more transactions", "num", len(newTxs), "totalPending", len(node.pendingTransactions)) - } + node.pendingTxMutex.Lock() + node.pendingTransactions = append(node.pendingTransactions, newTxs...) + node.reducePendingTransactions() + node.pendingTxMutex.Unlock() + utils.GetLogInstance().Info("Got more transactions", "num", len(newTxs), "totalPending", len(node.pendingTransactions)) } // AddPendingTransaction adds one new transaction to the pending transaction list. func (node *Node) AddPendingTransaction(newTx *types.Transaction) { - if node.NodeConfig.GetNetworkType() != nodeconfig.Mainnet { - node.addPendingTransactions(types.Transactions{newTx}) - utils.GetLogInstance().Debug("Got ONE more transaction", "totalPending", len(node.pendingTransactions)) - } + node.addPendingTransactions(types.Transactions{newTx}) + utils.GetLogInstance().Debug("Got ONE more transaction", "totalPending", len(node.pendingTransactions)) } // Take out a subset of valid transactions from the pending transaction list // Note the pending transaction list will then contain the rest of the txs func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Transactions { - if node.NodeConfig.GetNetworkType() == nodeconfig.Mainnet { - return types.Transactions{} - } node.pendingTxMutex.Lock() selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(node.pendingTransactions, core.ShardingSchedule.TxsThrottleConfig(), coinbase) diff --git a/node/node_newblock.go b/node/node_newblock.go index 451e48b8a..c07174cb5 100644 --- a/node/node_newblock.go +++ b/node/node_newblock.go @@ -8,7 +8,6 @@ import ( "github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core/types" - nodeconfig "github.com/harmony-one/harmony/internal/configs/node" "github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/utils" ) @@ -48,12 +47,9 @@ func (node *Node) WaitForConsensusReadyv2(readySignal chan struct{}, stopChan ch coinbase := node.Consensus.SelfAddress // Normal tx block consensus - selectedTxs := types.Transactions{} // Empty transaction list - if node.NodeConfig.GetNetworkType() != nodeconfig.Mainnet { - selectedTxs = node.getTransactionsForNewBlock(coinbase) - if err := node.Worker.UpdateCurrent(coinbase); err != nil { - utils.GetLogger().Error("Failed updating worker's state", "Error", err) - } + selectedTxs := node.getTransactionsForNewBlock(coinbase) + if err := node.Worker.UpdateCurrent(coinbase); err != nil { + utils.GetLogger().Error("Failed updating worker's state", "Error", err) } utils.GetLogInstance().Info("PROPOSING NEW BLOCK ------------------------------------------------", "blockNum", node.Blockchain().CurrentBlock().NumberU64()+1, "selectedTxs", len(selectedTxs)) if err := node.Worker.CommitTransactions(selectedTxs, coinbase); err != nil { @@ -71,11 +67,9 @@ func (node *Node) WaitForConsensusReadyv2(readySignal chan struct{}, stopChan ch viewID := node.Consensus.GetViewID() // add aggregated commit signatures from last block, except for the first two blocks - if node.NodeConfig.GetNetworkType() == nodeconfig.Mainnet { - if err = node.Worker.UpdateCurrent(coinbase); err != nil { - utils.GetLogger().Debug("Failed updating worker's state", "Error", err) - continue - } + if err = node.Worker.UpdateCurrent(coinbase); err != nil { + utils.GetLogger().Debug("Failed updating worker's state", "Error", err) + continue } newBlock, err = node.Worker.Commit(sig, mask, viewID, coinbase) From c632fd6c3b88a6ece1868b85cd93c102af1996aa Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 08:18:04 -0700 Subject: [PATCH 03/20] save recentTxsStats on node memory for per account/per block level transactions num tracking --- core/types/transaction.go | 7 +++++++ node/node.go | 20 +++++++++++++++++--- node/worker/worker.go | 8 ++++---- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/core/types/transaction.go b/core/types/transaction.go index 12ae4a06e..609b83044 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -295,6 +295,13 @@ func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) { // Transactions is a Transaction slice type for basic sorting. type Transactions []*Transaction +// RecentTxsStats is a recent transactions stats map tracking stats like BlockTxsCounts. +type RecentTxsStats map[uint64]BlockTxsCounts + +// BlockTxsCounts is a transactions counts map of +// the number of transactions made by each account in a block on this node. +type BlockTxsCounts map[common.Address]uint64 + // Len returns the length of s. func (s Transactions) Len() int { return len(s) } diff --git a/node/node.go b/node/node.go index 45480e6a7..d7da00799 100644 --- a/node/node.go +++ b/node/node.go @@ -92,6 +92,7 @@ type Node struct { BeaconBlockChannel chan *types.Block // The channel to send beacon blocks for non-beaconchain nodes pendingTransactions types.Transactions // All the transactions received but not yet processed for Consensus pendingTxMutex sync.Mutex + recentTxsStats types.RecentTxsStats DRand *drand.DRand // The instance for distributed randomness protocol // Shard databases @@ -226,9 +227,10 @@ func (node *Node) Beaconchain() *core.BlockChain { func (node *Node) reducePendingTransactions() { txPoolLimit := core.ShardingSchedule.MaxTxsPerBlockLimit() + curLen := len(node.pendingTransactions) + // If length of pendingTransactions is greater than TxPoolLimit then by greedy take the TxPoolLimit recent transactions. - if len(node.pendingTransactions) > txPoolLimit+txPoolLimit { - curLen := len(node.pendingTransactions) + if curLen > txPoolLimit+txPoolLimit { node.pendingTransactions = append(types.Transactions(nil), node.pendingTransactions[curLen-txPoolLimit:]...) utils.GetLogger().Info("mem stat reduce pending transaction") } @@ -253,16 +255,25 @@ func (node *Node) AddPendingTransaction(newTx *types.Transaction) { // Note the pending transaction list will then contain the rest of the txs func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Transactions { node.pendingTxMutex.Lock() - selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(node.pendingTransactions, core.ShardingSchedule.TxsThrottleConfig(), coinbase) + selected, unselected, invalid, blockTxsCounts := node.Worker.SelectTransactionsForNewBlock(node.pendingTransactions, core.ShardingSchedule.TxsThrottleConfig(), coinbase) node.pendingTransactions = unselected node.reducePendingTransactions() + node.recentTxsStats[node.Consensus.ChainReader.CurrentHeader().Number.Uint64()+1] = blockTxsCounts + for blockNum := range node.recentTxsStats { + blockNumPastHour := (time.Hour / time.Second) / node.BlockPeriod + if blockNum < node.Consensus.ChainReader.CurrentHeader().Number.Uint64()-uint64(blockNumPastHour) { + delete(node.recentTxsStats, blockNum) + } + } + utils.Logger().Info(). Int("remainPending", len(node.pendingTransactions)). Int("selected", len(selected)). Int("invalidDiscarded", len(invalid)). Msg("Selecting Transactions") node.pendingTxMutex.Unlock() + return selected } @@ -328,6 +339,9 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc node.BlockChannel = make(chan *types.Block) node.ConfirmedBlockChannel = make(chan *types.Block) node.BeaconBlockChannel = make(chan *types.Block) + + node.recentTxsStats = make(types.RecentTxsStats) + node.TxPool = core.NewTxPool(core.DefaultTxPoolConfig, node.Blockchain().Config(), chain) node.Worker = worker.New(node.Blockchain().Config(), chain, node.Consensus, node.Consensus.ShardID) diff --git a/node/worker/worker.go b/node/worker/worker.go index 50eeb6ea6..2279c309e 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -46,7 +46,7 @@ type Worker struct { // Returns a tuple where the first value is the txs sender account address, // the second is the throttling result enum for the transaction of interest. // Throttling happens based on the amount, frequency, etc. -func (w *Worker) throttleTxs(selected types.Transactions, txsThrottleConfig *shardingconfig.TxsThrottleConfig, txnCnts map[common.Address]uint64, tx *types.Transaction) (common.Address, shardingconfig.TxThrottleFlag) { +func (w *Worker) throttleTxs(selected types.Transactions, txsThrottleConfig *shardingconfig.TxsThrottleConfig, txnCnts types.BlockTxsCounts, tx *types.Transaction) (common.Address, shardingconfig.TxThrottleFlag) { chainID := tx.ChainID() // Depending on the presence of the chain ID, sign with EIP155 or homestead var s types.Signer @@ -93,13 +93,13 @@ func (w *Worker) throttleTxs(selected types.Transactions, txsThrottleConfig *sha } // SelectTransactionsForNewBlock selects transactions for new block. -func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, txsThrottleConfig *shardingconfig.TxsThrottleConfig, coinbase common.Address) (types.Transactions, types.Transactions, types.Transactions) { +func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, txsThrottleConfig *shardingconfig.TxsThrottleConfig, coinbase common.Address) (types.Transactions, types.Transactions, types.Transactions, types.BlockTxsCounts) { if w.current.gasPool == nil { w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) } // used for per account transaction frequency throttling - txnCnts := make(map[common.Address]uint64) + txnCnts := types.BlockTxsCounts{} selected := types.Transactions{} unselected := types.Transactions{} @@ -142,7 +142,7 @@ func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, txsThrott } } } - return selected, unselected, invalid + return selected, unselected, invalid, txnCnts } func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { From 1d48c7c42c018fb1003f7d53de184ed7e59255e3 Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 08:45:42 -0700 Subject: [PATCH 04/20] added throttling by num transactions per account past hour --- node/node.go | 16 ++++++++++------ node/worker/worker.go | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/node/node.go b/node/node.go index d7da00799..1c8b2df35 100644 --- a/node/node.go +++ b/node/node.go @@ -255,17 +255,21 @@ func (node *Node) AddPendingTransaction(newTx *types.Transaction) { // Note the pending transaction list will then contain the rest of the txs func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Transactions { node.pendingTxMutex.Lock() - selected, unselected, invalid, blockTxsCounts := node.Worker.SelectTransactionsForNewBlock(node.pendingTransactions, core.ShardingSchedule.TxsThrottleConfig(), coinbase) - node.pendingTransactions = unselected - node.reducePendingTransactions() - node.recentTxsStats[node.Consensus.ChainReader.CurrentHeader().Number.Uint64()+1] = blockTxsCounts + // update recentTxsStats and initiailize for the new block + newBlockNum := node.Consensus.ChainReader.CurrentHeader().Number.Uint64() + 1 for blockNum := range node.recentTxsStats { - blockNumPastHour := (time.Hour / time.Second) / node.BlockPeriod - if blockNum < node.Consensus.ChainReader.CurrentHeader().Number.Uint64()-uint64(blockNumPastHour) { + blockNumHourAgo := (time.Hour / time.Second) / node.BlockPeriod + if blockNum < node.Consensus.ChainReader.CurrentHeader().Number.Uint64()-uint64(blockNumHourAgo) { delete(node.recentTxsStats, blockNum) } } + node.recentTxsStats[newBlockNum] = types.BlockTxsCounts{} + + selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(newBlockNum, node.pendingTransactions, node.recentTxsStats, core.ShardingSchedule.TxsThrottleConfig(), coinbase) + + node.pendingTransactions = unselected + node.reducePendingTransactions() utils.Logger().Info(). Int("remainPending", len(node.pendingTransactions)). diff --git a/node/worker/worker.go b/node/worker/worker.go index 2279c309e..76032387d 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -46,7 +46,7 @@ type Worker struct { // Returns a tuple where the first value is the txs sender account address, // the second is the throttling result enum for the transaction of interest. // Throttling happens based on the amount, frequency, etc. -func (w *Worker) throttleTxs(selected types.Transactions, txsThrottleConfig *shardingconfig.TxsThrottleConfig, txnCnts types.BlockTxsCounts, tx *types.Transaction) (common.Address, shardingconfig.TxThrottleFlag) { +func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.RecentTxsStats, txsThrottleConfig *shardingconfig.TxsThrottleConfig, tx *types.Transaction) (common.Address, shardingconfig.TxThrottleFlag) { chainID := tx.ChainID() // Depending on the presence of the chain ID, sign with EIP155 or homestead var s types.Signer @@ -82,7 +82,11 @@ func (w *Worker) throttleTxs(selected types.Transactions, txsThrottleConfig *sha } // throttle too large transaction - if txnCnts[sender] >= (*txsThrottleConfig).MaxTxsPerAccountInBlockLimit { + var numTxsPastHour uint64 + for _, blockTxsCounts := range recentTxsStats { + numTxsPastHour += blockTxsCounts[sender] + } + if numTxsPastHour >= (*txsThrottleConfig).MaxTxsPerAccountInBlockLimit { utils.Logger().Debug(). Uint64("MaxTxsPerAccountInBlockLimit", (*txsThrottleConfig).MaxTxsPerAccountInBlockLimit). Msg("Throttling tx with max txs per account in a single block limit") @@ -93,14 +97,11 @@ func (w *Worker) throttleTxs(selected types.Transactions, txsThrottleConfig *sha } // SelectTransactionsForNewBlock selects transactions for new block. -func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, txsThrottleConfig *shardingconfig.TxsThrottleConfig, coinbase common.Address) (types.Transactions, types.Transactions, types.Transactions, types.BlockTxsCounts) { +func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Transactions, recentTxsStats types.RecentTxsStats, txsThrottleConfig *shardingconfig.TxsThrottleConfig, coinbase common.Address) (types.Transactions, types.Transactions, types.Transactions) { if w.current.gasPool == nil { w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) } - // used for per account transaction frequency throttling - txnCnts := types.BlockTxsCounts{} - selected := types.Transactions{} unselected := types.Transactions{} invalid := types.Transactions{} @@ -109,7 +110,7 @@ func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, txsThrott invalid = append(invalid, tx) } - sender, flag := w.throttleTxs(selected, txsThrottleConfig, txnCnts, tx) + sender, flag := w.throttleTxs(selected, recentTxsStats, txsThrottleConfig, tx) switch flag { case shardingconfig.Unselect: unselected = append(unselected, tx) @@ -138,11 +139,11 @@ func (w *Worker) SelectTransactionsForNewBlock(txs types.Transactions, txsThrott Msg("Transaction Throttle flag") } else { selected = append(selected, tx) - txnCnts[sender]++ + recentTxsStats[newBlockNum][sender]++ } } } - return selected, unselected, invalid, txnCnts + return selected, unselected, invalid } func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { From b4c4f76546f58574f457488ed1e3515445b9ca24 Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 08:47:08 -0700 Subject: [PATCH 05/20] simple symbol renaming for txThrottleFlag --- internal/configs/sharding/shardingconfig.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index 060fa07c5..5ecec75ff 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -65,21 +65,21 @@ type TxThrottleFlag int // Enum for different TxThrottleFlag const ( - Select TxThrottleFlag = iota - Unselect - Invalid + TxSelect TxThrottleFlag = iota + TxUnselect + TxInvalid ) func (result TxThrottleFlag) String() string { switch result { - case Select: - return "Select" - case Unselect: - return "Unselect" - case Invalid: - return "Invalid" + case TxSelect: + return "TxSelect" + case TxUnselect: + return "TxUnselect" + case TxInvalid: + return "TxInvalid" } - return "Unknown" + return "TxThrottleUnknown" } // TxsThrottleConfig contains configuration for throttling pending transactions per node block From 987306a9f84e11d0ae5810da022467a20145c89a Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 08:51:09 -0700 Subject: [PATCH 06/20] rename tx throttline configuration key name to MaxNumTxsPerAccountPastHourLimit --- internal/configs/sharding/fixedschedule.go | 10 +++++----- internal/configs/sharding/localnet.go | 16 ++++++++-------- internal/configs/sharding/mainnet.go | 16 ++++++++-------- internal/configs/sharding/shardingconfig.go | 6 +++--- internal/configs/sharding/testnet.go | 16 ++++++++-------- node/worker/worker.go | 4 ++-- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/internal/configs/sharding/fixedschedule.go b/internal/configs/sharding/fixedschedule.go index 8f2b8d198..da63e28b3 100644 --- a/internal/configs/sharding/fixedschedule.go +++ b/internal/configs/sharding/fixedschedule.go @@ -40,8 +40,8 @@ func (s fixedSchedule) MaxTxAmountLimit() *big.Int { return amountBigInt } -func (s fixedSchedule) MaxTxsPerAccountInBlockLimit() uint64 { - return mainnetMaxTxsPerAccountInBlockLimit +func (s fixedSchedule) MaxNumTxsPerAccountPastHourLimit() uint64 { + return mainnetMaxNumTxsPerAccountPastHourLimit } func (s fixedSchedule) MaxTxsPerBlockLimit() int { @@ -50,9 +50,9 @@ func (s fixedSchedule) MaxTxsPerBlockLimit() int { func (s fixedSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: s.MaxTxAmountLimit(), - MaxTxsPerAccountInBlockLimit: s.MaxTxsPerAccountInBlockLimit(), - MaxTxsPerBlockLimit: s.MaxTxsPerBlockLimit(), + MaxTxAmountLimit: s.MaxTxAmountLimit(), + MaxNumTxsPerAccountPastHourLimit: s.MaxNumTxsPerAccountPastHourLimit(), + MaxTxsPerBlockLimit: s.MaxTxsPerBlockLimit(), } } diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index a47562cce..967ea70b1 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -20,9 +20,9 @@ const ( localnetEpochBlock1 = 20 twoOne = 5 - localnetMaxTxAmountLimit = 1e2 // unit is in One - localnetMaxTxsPerAccountInBlockLimit = 2 - localnetMaxTxsPerBlockLimit = 8000 + localnetMaxTxAmountLimit = 1e2 // unit is in One + localnetMaxNumTxsPerAccountPastHourLimit = 2 + localnetMaxTxsPerBlockLimit = 8000 ) func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -68,8 +68,8 @@ func (ls localnetSchedule) MaxTxAmountLimit() *big.Int { return amountBigInt } -func (ls localnetSchedule) MaxTxsPerAccountInBlockLimit() uint64 { - return localnetMaxTxsPerAccountInBlockLimit +func (ls localnetSchedule) MaxNumTxsPerAccountPastHourLimit() uint64 { + return localnetMaxNumTxsPerAccountPastHourLimit } func (ls localnetSchedule) MaxTxsPerBlockLimit() int { @@ -78,9 +78,9 @@ func (ls localnetSchedule) MaxTxsPerBlockLimit() int { func (ls localnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: ls.MaxTxAmountLimit(), - MaxTxsPerAccountInBlockLimit: ls.MaxTxsPerAccountInBlockLimit(), - MaxTxsPerBlockLimit: ls.MaxTxsPerBlockLimit(), + MaxTxAmountLimit: ls.MaxTxAmountLimit(), + MaxNumTxsPerAccountPastHourLimit: ls.MaxNumTxsPerAccountPastHourLimit(), + MaxTxsPerBlockLimit: ls.MaxTxsPerBlockLimit(), } } diff --git a/internal/configs/sharding/mainnet.go b/internal/configs/sharding/mainnet.go index b35252234..d7e78d541 100644 --- a/internal/configs/sharding/mainnet.go +++ b/internal/configs/sharding/mainnet.go @@ -13,9 +13,9 @@ const ( mainnetV1Epoch = 1 mainnetV2Epoch = 5 - mainnetMaxTxAmountLimit = 1e3 // unit is in One - mainnetMaxTxsPerAccountInBlockLimit = 10 - mainnetMaxTxsPerBlockLimit = 8000 + mainnetMaxTxAmountLimit = 1e3 // unit is in One + mainnetMaxNumTxsPerAccountPastHourLimit = 10 + mainnetMaxTxsPerBlockLimit = 8000 ) // MainnetSchedule is the mainnet sharding configuration schedule. @@ -68,8 +68,8 @@ func (ms mainnetSchedule) MaxTxAmountLimit() *big.Int { return amountBigInt } -func (ms mainnetSchedule) MaxTxsPerAccountInBlockLimit() uint64 { - return mainnetMaxTxsPerAccountInBlockLimit +func (ms mainnetSchedule) MaxNumTxsPerAccountPastHourLimit() uint64 { + return mainnetMaxNumTxsPerAccountPastHourLimit } func (ms mainnetSchedule) MaxTxsPerBlockLimit() int { @@ -78,9 +78,9 @@ func (ms mainnetSchedule) MaxTxsPerBlockLimit() int { func (ms mainnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: ms.MaxTxAmountLimit(), - MaxTxsPerAccountInBlockLimit: ms.MaxTxsPerAccountInBlockLimit(), - MaxTxsPerBlockLimit: ms.MaxTxsPerBlockLimit(), + MaxTxAmountLimit: ms.MaxTxAmountLimit(), + MaxNumTxsPerAccountPastHourLimit: ms.MaxNumTxsPerAccountPastHourLimit(), + MaxTxsPerBlockLimit: ms.MaxTxsPerBlockLimit(), } } diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index 5ecec75ff..cbc8cb05f 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -26,7 +26,7 @@ type Schedule interface { MaxTxAmountLimit() *big.Int // Max number of transactions of a particular account per block level - MaxTxsPerAccountInBlockLimit() uint64 + MaxNumTxsPerAccountPastHourLimit() uint64 // Max total number of transactions in a block MaxTxsPerBlockLimit() int @@ -87,8 +87,8 @@ type TxsThrottleConfig struct { // Max amount limit for a valid transaction MaxTxAmountLimit *big.Int - // Max number of transactions of a particular account per block level - MaxTxsPerAccountInBlockLimit uint64 + // Max number of transactions of a particular account for the past hour + MaxNumTxsPerAccountPastHourLimit uint64 // Max total number of transactions in a block MaxTxsPerBlockLimit int diff --git a/internal/configs/sharding/testnet.go b/internal/configs/sharding/testnet.go index de8710c44..80b37c14f 100644 --- a/internal/configs/sharding/testnet.go +++ b/internal/configs/sharding/testnet.go @@ -20,9 +20,9 @@ const ( testnetEpochBlock1 = 78 threeOne = 111 - testnetMaxTxAmountLimit = 1e3 // unit is in One - testnetMaxTxsPerAccountInBlockLimit = 10 - testnetMaxTxsPerBlockLimit = 8000 + testnetMaxTxAmountLimit = 1e3 // unit is in One + testnetMaxNumTxsPerAccountPastHourLimit = 10 + testnetMaxTxsPerBlockLimit = 8000 ) func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -69,8 +69,8 @@ func (ts testnetSchedule) MaxTxAmountLimit() *big.Int { return amountBigInt } -func (ts testnetSchedule) MaxTxsPerAccountInBlockLimit() uint64 { - return testnetMaxTxsPerAccountInBlockLimit +func (ts testnetSchedule) MaxNumTxsPerAccountPastHourLimit() uint64 { + return testnetMaxNumTxsPerAccountPastHourLimit } func (ts testnetSchedule) MaxTxsPerBlockLimit() int { @@ -79,9 +79,9 @@ func (ts testnetSchedule) MaxTxsPerBlockLimit() int { func (ts testnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: ts.MaxTxAmountLimit(), - MaxTxsPerAccountInBlockLimit: ts.MaxTxsPerAccountInBlockLimit(), - MaxTxsPerBlockLimit: ts.MaxTxsPerBlockLimit(), + MaxTxAmountLimit: ts.MaxTxAmountLimit(), + MaxNumTxsPerAccountPastHourLimit: ts.MaxNumTxsPerAccountPastHourLimit(), + MaxTxsPerBlockLimit: ts.MaxTxsPerBlockLimit(), } } diff --git a/node/worker/worker.go b/node/worker/worker.go index 76032387d..d3c6ab9bc 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -86,9 +86,9 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R for _, blockTxsCounts := range recentTxsStats { numTxsPastHour += blockTxsCounts[sender] } - if numTxsPastHour >= (*txsThrottleConfig).MaxTxsPerAccountInBlockLimit { + if numTxsPastHour >= (*txsThrottleConfig).MaxNumTxsPerAccountPastHourLimit { utils.Logger().Debug(). - Uint64("MaxTxsPerAccountInBlockLimit", (*txsThrottleConfig).MaxTxsPerAccountInBlockLimit). + Uint64("MaxNumTxsPerAccountPastHourLimit", (*txsThrottleConfig).MaxNumTxsPerAccountPastHourLimit). Msg("Throttling tx with max txs per account in a single block limit") return sender, shardingconfig.Unselect } From dae2e393c90d32ab650d76aceef8bce4cc90f45e Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 08:52:09 -0700 Subject: [PATCH 07/20] rename tx throttline configuration key name to localnetMaxNumRecentTxsPerAccountLimit --- internal/configs/sharding/fixedschedule.go | 10 +++++----- internal/configs/sharding/localnet.go | 16 ++++++++-------- internal/configs/sharding/mainnet.go | 16 ++++++++-------- internal/configs/sharding/shardingconfig.go | 4 ++-- internal/configs/sharding/testnet.go | 16 ++++++++-------- node/node.go | 2 -- node/worker/worker.go | 18 +++++++++--------- 7 files changed, 40 insertions(+), 42 deletions(-) diff --git a/internal/configs/sharding/fixedschedule.go b/internal/configs/sharding/fixedschedule.go index da63e28b3..3e9d426d0 100644 --- a/internal/configs/sharding/fixedschedule.go +++ b/internal/configs/sharding/fixedschedule.go @@ -40,8 +40,8 @@ func (s fixedSchedule) MaxTxAmountLimit() *big.Int { return amountBigInt } -func (s fixedSchedule) MaxNumTxsPerAccountPastHourLimit() uint64 { - return mainnetMaxNumTxsPerAccountPastHourLimit +func (s fixedSchedule) MaxNumRecentTxsPerAccountLimit() uint64 { + return mainnetMaxNumRecentTxsPerAccountLimit } func (s fixedSchedule) MaxTxsPerBlockLimit() int { @@ -50,9 +50,9 @@ func (s fixedSchedule) MaxTxsPerBlockLimit() int { func (s fixedSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: s.MaxTxAmountLimit(), - MaxNumTxsPerAccountPastHourLimit: s.MaxNumTxsPerAccountPastHourLimit(), - MaxTxsPerBlockLimit: s.MaxTxsPerBlockLimit(), + MaxTxAmountLimit: s.MaxTxAmountLimit(), + MaxNumRecentTxsPerAccountLimit: s.MaxNumRecentTxsPerAccountLimit(), + MaxTxsPerBlockLimit: s.MaxTxsPerBlockLimit(), } } diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index 967ea70b1..524866b1f 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -20,9 +20,9 @@ const ( localnetEpochBlock1 = 20 twoOne = 5 - localnetMaxTxAmountLimit = 1e2 // unit is in One - localnetMaxNumTxsPerAccountPastHourLimit = 2 - localnetMaxTxsPerBlockLimit = 8000 + localnetMaxTxAmountLimit = 1e2 // unit is in One + localnetMaxNumRecentTxsPerAccountLimit = 2 + localnetMaxTxsPerBlockLimit = 8000 ) func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -68,8 +68,8 @@ func (ls localnetSchedule) MaxTxAmountLimit() *big.Int { return amountBigInt } -func (ls localnetSchedule) MaxNumTxsPerAccountPastHourLimit() uint64 { - return localnetMaxNumTxsPerAccountPastHourLimit +func (ls localnetSchedule) MaxNumRecentTxsPerAccountLimit() uint64 { + return localnetMaxNumRecentTxsPerAccountLimit } func (ls localnetSchedule) MaxTxsPerBlockLimit() int { @@ -78,9 +78,9 @@ func (ls localnetSchedule) MaxTxsPerBlockLimit() int { func (ls localnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: ls.MaxTxAmountLimit(), - MaxNumTxsPerAccountPastHourLimit: ls.MaxNumTxsPerAccountPastHourLimit(), - MaxTxsPerBlockLimit: ls.MaxTxsPerBlockLimit(), + MaxTxAmountLimit: ls.MaxTxAmountLimit(), + MaxNumRecentTxsPerAccountLimit: ls.MaxNumRecentTxsPerAccountLimit(), + MaxTxsPerBlockLimit: ls.MaxTxsPerBlockLimit(), } } diff --git a/internal/configs/sharding/mainnet.go b/internal/configs/sharding/mainnet.go index d7e78d541..e6999b083 100644 --- a/internal/configs/sharding/mainnet.go +++ b/internal/configs/sharding/mainnet.go @@ -13,9 +13,9 @@ const ( mainnetV1Epoch = 1 mainnetV2Epoch = 5 - mainnetMaxTxAmountLimit = 1e3 // unit is in One - mainnetMaxNumTxsPerAccountPastHourLimit = 10 - mainnetMaxTxsPerBlockLimit = 8000 + mainnetMaxTxAmountLimit = 1e3 // unit is in One + mainnetMaxNumRecentTxsPerAccountLimit = 10 + mainnetMaxTxsPerBlockLimit = 8000 ) // MainnetSchedule is the mainnet sharding configuration schedule. @@ -68,8 +68,8 @@ func (ms mainnetSchedule) MaxTxAmountLimit() *big.Int { return amountBigInt } -func (ms mainnetSchedule) MaxNumTxsPerAccountPastHourLimit() uint64 { - return mainnetMaxNumTxsPerAccountPastHourLimit +func (ms mainnetSchedule) MaxNumRecentTxsPerAccountLimit() uint64 { + return mainnetMaxNumRecentTxsPerAccountLimit } func (ms mainnetSchedule) MaxTxsPerBlockLimit() int { @@ -78,9 +78,9 @@ func (ms mainnetSchedule) MaxTxsPerBlockLimit() int { func (ms mainnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: ms.MaxTxAmountLimit(), - MaxNumTxsPerAccountPastHourLimit: ms.MaxNumTxsPerAccountPastHourLimit(), - MaxTxsPerBlockLimit: ms.MaxTxsPerBlockLimit(), + MaxTxAmountLimit: ms.MaxTxAmountLimit(), + MaxNumRecentTxsPerAccountLimit: ms.MaxNumRecentTxsPerAccountLimit(), + MaxTxsPerBlockLimit: ms.MaxTxsPerBlockLimit(), } } diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index cbc8cb05f..11fa24f7b 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -26,7 +26,7 @@ type Schedule interface { MaxTxAmountLimit() *big.Int // Max number of transactions of a particular account per block level - MaxNumTxsPerAccountPastHourLimit() uint64 + MaxNumRecentTxsPerAccountLimit() uint64 // Max total number of transactions in a block MaxTxsPerBlockLimit() int @@ -88,7 +88,7 @@ type TxsThrottleConfig struct { MaxTxAmountLimit *big.Int // Max number of transactions of a particular account for the past hour - MaxNumTxsPerAccountPastHourLimit uint64 + MaxNumRecentTxsPerAccountLimit uint64 // Max total number of transactions in a block MaxTxsPerBlockLimit int diff --git a/internal/configs/sharding/testnet.go b/internal/configs/sharding/testnet.go index 80b37c14f..5cc544aa5 100644 --- a/internal/configs/sharding/testnet.go +++ b/internal/configs/sharding/testnet.go @@ -20,9 +20,9 @@ const ( testnetEpochBlock1 = 78 threeOne = 111 - testnetMaxTxAmountLimit = 1e3 // unit is in One - testnetMaxNumTxsPerAccountPastHourLimit = 10 - testnetMaxTxsPerBlockLimit = 8000 + testnetMaxTxAmountLimit = 1e3 // unit is in One + testnetMaxNumRecentTxsPerAccountLimit = 10 + testnetMaxTxsPerBlockLimit = 8000 ) func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -69,8 +69,8 @@ func (ts testnetSchedule) MaxTxAmountLimit() *big.Int { return amountBigInt } -func (ts testnetSchedule) MaxNumTxsPerAccountPastHourLimit() uint64 { - return testnetMaxNumTxsPerAccountPastHourLimit +func (ts testnetSchedule) MaxNumRecentTxsPerAccountLimit() uint64 { + return testnetMaxNumRecentTxsPerAccountLimit } func (ts testnetSchedule) MaxTxsPerBlockLimit() int { @@ -79,9 +79,9 @@ func (ts testnetSchedule) MaxTxsPerBlockLimit() int { func (ts testnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: ts.MaxTxAmountLimit(), - MaxNumTxsPerAccountPastHourLimit: ts.MaxNumTxsPerAccountPastHourLimit(), - MaxTxsPerBlockLimit: ts.MaxTxsPerBlockLimit(), + MaxTxAmountLimit: ts.MaxTxAmountLimit(), + MaxNumRecentTxsPerAccountLimit: ts.MaxNumRecentTxsPerAccountLimit(), + MaxTxsPerBlockLimit: ts.MaxTxsPerBlockLimit(), } } diff --git a/node/node.go b/node/node.go index 1c8b2df35..79b6c69d9 100644 --- a/node/node.go +++ b/node/node.go @@ -344,8 +344,6 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc node.ConfirmedBlockChannel = make(chan *types.Block) node.BeaconBlockChannel = make(chan *types.Block) - node.recentTxsStats = make(types.RecentTxsStats) - node.TxPool = core.NewTxPool(core.DefaultTxPoolConfig, node.Blockchain().Config(), chain) node.Worker = worker.New(node.Blockchain().Config(), chain, node.Consensus, node.Consensus.ShardID) diff --git a/node/worker/worker.go b/node/worker/worker.go index d3c6ab9bc..9c735eb9e 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -69,7 +69,7 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R utils.Logger().Debug(). Int("MaxTxsPerBlockLimit", (*txsThrottleConfig).MaxTxsPerBlockLimit). Msg("Throttling tx with max txs per block limit") - return sender, shardingconfig.Unselect + return sender, shardingconfig.TxUnselect } // throttle a single sender sending too many transactions in one block @@ -78,7 +78,7 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R Uint64("MaxTxAmountLimit", (*txsThrottleConfig).MaxTxAmountLimit.Uint64()). Uint64("Tx amount", tx.Value().Uint64()). Msg("Throttling tx with max amount limit") - return sender, shardingconfig.Invalid + return sender, shardingconfig.TxInvalid } // throttle too large transaction @@ -86,14 +86,14 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R for _, blockTxsCounts := range recentTxsStats { numTxsPastHour += blockTxsCounts[sender] } - if numTxsPastHour >= (*txsThrottleConfig).MaxNumTxsPerAccountPastHourLimit { + if numTxsPastHour >= (*txsThrottleConfig).MaxNumRecentTxsPerAccountLimit { utils.Logger().Debug(). - Uint64("MaxNumTxsPerAccountPastHourLimit", (*txsThrottleConfig).MaxNumTxsPerAccountPastHourLimit). + Uint64("MaxNumRecentTxsPerAccountLimit", (*txsThrottleConfig).MaxNumRecentTxsPerAccountLimit). Msg("Throttling tx with max txs per account in a single block limit") - return sender, shardingconfig.Unselect + return sender, shardingconfig.TxUnselect } - return sender, shardingconfig.Select + return sender, shardingconfig.TxSelect } // SelectTransactionsForNewBlock selects transactions for new block. @@ -112,21 +112,21 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra sender, flag := w.throttleTxs(selected, recentTxsStats, txsThrottleConfig, tx) switch flag { - case shardingconfig.Unselect: + case shardingconfig.TxUnselect: unselected = append(unselected, tx) utils.Logger().Info(). Str("Transaction Id", tx.Hash().Hex()). Str("txThrottleFlag", flag.String()). Msg("Transaction Throttle flag") - case shardingconfig.Invalid: + case shardingconfig.TxInvalid: invalid = append(invalid, tx) utils.Logger().Info(). Str("txThrottleFlag", flag.String()). Str("Transaction Id", tx.Hash().Hex()). Msg("Transaction Throttle flag") - case shardingconfig.Select: + case shardingconfig.TxSelect: snap := w.current.state.Snapshot() _, err := w.commitTransaction(tx, coinbase) if err != nil { From f41a2e62039dd4025ca4b4156b6df00ff2b2446f Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 10:51:57 -0700 Subject: [PATCH 08/20] removed zero logger for the flow added in this pr --- node/node.go | 10 ++++----- node/worker/worker.go | 48 ++++++++++++++++++++----------------------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/node/node.go b/node/node.go index 79b6c69d9..8078f6fb1 100644 --- a/node/node.go +++ b/node/node.go @@ -271,11 +271,11 @@ func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Tran node.pendingTransactions = unselected node.reducePendingTransactions() - utils.Logger().Info(). - Int("remainPending", len(node.pendingTransactions)). - Int("selected", len(selected)). - Int("invalidDiscarded", len(invalid)). - Msg("Selecting Transactions") + utils.GetLogInstance().Info( + "msg", "Selecting Transactions", + "newBlockNum", newBlockNum, + "remainPending", len(node.pendingTransactions), + "invalidDiscarded", len(invalid)) node.pendingTxMutex.Unlock() return selected diff --git a/node/worker/worker.go b/node/worker/worker.go index 9c735eb9e..14e31ebe0 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -59,25 +59,25 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R var sender common.Address msg, err := tx.AsMessage(s) if err != nil { - utils.Logger().Error().Msg("Error when parsing tx into message") + utils.GetLogInstance().Error("Error when parsing tx into message", "msg", err) } else { sender = msg.From() } // already selected max num txs if len(selected) > (*txsThrottleConfig).MaxTxsPerBlockLimit { - utils.Logger().Debug(). - Int("MaxTxsPerBlockLimit", (*txsThrottleConfig).MaxTxsPerBlockLimit). - Msg("Throttling tx with max txs per block limit") + utils.GetLogInstance().Info( + "msg", "Throttling tx with max txs per block limit", + "MaxTxsPerBlockLimit", txsThrottleConfig.MaxTxsPerBlockLimit) return sender, shardingconfig.TxUnselect } // throttle a single sender sending too many transactions in one block - if ((*txsThrottleConfig).MaxTxAmountLimit).Cmp(tx.Value()) < 0 { - utils.Logger().Debug(). - Uint64("MaxTxAmountLimit", (*txsThrottleConfig).MaxTxAmountLimit.Uint64()). - Uint64("Tx amount", tx.Value().Uint64()). - Msg("Throttling tx with max amount limit") + if (txsThrottleConfig.MaxTxAmountLimit).Cmp(tx.Value()) < 0 { + utils.GetLogInstance().Info( + "msg", "Throttling tx with max amount limit", + "MaxTxAmountLimit", txsThrottleConfig.MaxTxAmountLimit.Uint64(), + "Tx amount", tx.Value().Uint64()) return sender, shardingconfig.TxInvalid } @@ -86,10 +86,10 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R for _, blockTxsCounts := range recentTxsStats { numTxsPastHour += blockTxsCounts[sender] } - if numTxsPastHour >= (*txsThrottleConfig).MaxNumRecentTxsPerAccountLimit { - utils.Logger().Debug(). - Uint64("MaxNumRecentTxsPerAccountLimit", (*txsThrottleConfig).MaxNumRecentTxsPerAccountLimit). - Msg("Throttling tx with max txs per account in a single block limit") + if numTxsPastHour >= txsThrottleConfig.MaxNumRecentTxsPerAccountLimit { + utils.GetLogInstance().Info( + "msg", "Throttling tx with max txs per account in a single block limit", + "MaxNumRecentTxsPerAccountLimit", txsThrottleConfig.MaxNumRecentTxsPerAccountLimit) return sender, shardingconfig.TxUnselect } @@ -114,17 +114,9 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra switch flag { case shardingconfig.TxUnselect: unselected = append(unselected, tx) - utils.Logger().Info(). - Str("Transaction Id", tx.Hash().Hex()). - Str("txThrottleFlag", flag.String()). - Msg("Transaction Throttle flag") case shardingconfig.TxInvalid: invalid = append(invalid, tx) - utils.Logger().Info(). - Str("txThrottleFlag", flag.String()). - Str("Transaction Id", tx.Hash().Hex()). - Msg("Transaction Throttle flag") case shardingconfig.TxSelect: snap := w.current.state.Snapshot() @@ -132,16 +124,20 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra if err != nil { w.current.state.RevertToSnapshot(snap) invalid = append(invalid, tx) - utils.Logger().Error(). - Err(err). - Str("Transaction Id", tx.Hash().Hex()). - Str("txThrottleFlag", flag.String()). - Msg("Transaction Throttle flag") + } else { selected = append(selected, tx) recentTxsStats[newBlockNum][sender]++ } } + + // log invalid or unselected txs + if flag == shardingconfig.TxUnselect || flag == shardingconfig.TxInvalid { + utils.GetLogInstance().Info( + "msg", "Transaction Throttle flag", + "Transaction Id", tx.Hash().Hex(), + "txThrottleFlag", flag.String()) + } } return selected, unselected, invalid } From c48f0bea46d0696fe02826fb8c4b377512043c0e Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 10:56:06 -0700 Subject: [PATCH 09/20] fix nil seg fault breaking consensus --- node/node.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/node/node.go b/node/node.go index 8078f6fb1..030abceb2 100644 --- a/node/node.go +++ b/node/node.go @@ -264,7 +264,7 @@ func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Tran delete(node.recentTxsStats, blockNum) } } - node.recentTxsStats[newBlockNum] = types.BlockTxsCounts{} + node.recentTxsStats[newBlockNum] = make(types.BlockTxsCounts) selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(newBlockNum, node.pendingTransactions, node.recentTxsStats, core.ShardingSchedule.TxsThrottleConfig(), coinbase) @@ -344,6 +344,7 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc node.ConfirmedBlockChannel = make(chan *types.Block) node.BeaconBlockChannel = make(chan *types.Block) + node.recentTxsStats = make(types.RecentTxsStats) node.TxPool = core.NewTxPool(core.DefaultTxPoolConfig, node.Blockchain().Config(), chain) node.Worker = worker.New(node.Blockchain().Config(), chain, node.Consensus, node.Consensus.ShardID) From 9da6f5624cb19e602b833fbbc1a97d2daa8bcd66 Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 11:50:07 -0700 Subject: [PATCH 10/20] fix max big int limit comparison issue with overflow --- internal/configs/sharding/fixedschedule.go | 6 +++--- internal/configs/sharding/localnet.go | 8 +++---- internal/configs/sharding/mainnet.go | 8 +++---- internal/configs/sharding/shardingconfig.go | 4 ++-- internal/configs/sharding/testnet.go | 8 +++---- node/node.go | 9 ++++---- node/worker/worker.go | 24 ++++++++++----------- 7 files changed, 33 insertions(+), 34 deletions(-) diff --git a/internal/configs/sharding/fixedschedule.go b/internal/configs/sharding/fixedschedule.go index 3e9d426d0..74969e0ff 100644 --- a/internal/configs/sharding/fixedschedule.go +++ b/internal/configs/sharding/fixedschedule.go @@ -34,8 +34,8 @@ func (s fixedSchedule) IsLastBlock(blockNum uint64) bool { return blockNum%blocks == blocks-1 } -func (s fixedSchedule) MaxTxAmountLimit() *big.Int { - amountBigInt := big.NewInt(int64(mainnetMaxTxAmountLimit * denominations.Nano)) +func (s fixedSchedule) MaxTxAmountNanoLimit() *big.Int { + amountBigInt := big.NewInt(mainnetMaxTxAmountNanoLimit) amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) return amountBigInt } @@ -50,7 +50,7 @@ func (s fixedSchedule) MaxTxsPerBlockLimit() int { func (s fixedSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: s.MaxTxAmountLimit(), + MaxTxAmountNanoLimit: s.MaxTxAmountNanoLimit(), MaxNumRecentTxsPerAccountLimit: s.MaxNumRecentTxsPerAccountLimit(), MaxTxsPerBlockLimit: s.MaxTxsPerBlockLimit(), } diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index 524866b1f..930fec25d 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -20,7 +20,7 @@ const ( localnetEpochBlock1 = 20 twoOne = 5 - localnetMaxTxAmountLimit = 1e2 // unit is in One + localnetMaxTxAmountNanoLimit = 1e2 // unit is in One localnetMaxNumRecentTxsPerAccountLimit = 2 localnetMaxTxsPerBlockLimit = 8000 ) @@ -62,8 +62,8 @@ func (ls localnetSchedule) IsLastBlock(blockNum uint64) bool { } } -func (ls localnetSchedule) MaxTxAmountLimit() *big.Int { - amountBigInt := big.NewInt(int64(localnetMaxTxAmountLimit * denominations.Nano)) +func (ls localnetSchedule) MaxTxAmountNanoLimit() *big.Int { + amountBigInt := big.NewInt(localnetMaxTxAmountNanoLimit) amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) return amountBigInt } @@ -78,7 +78,7 @@ func (ls localnetSchedule) MaxTxsPerBlockLimit() int { func (ls localnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: ls.MaxTxAmountLimit(), + MaxTxAmountNanoLimit: ls.MaxTxAmountNanoLimit(), MaxNumRecentTxsPerAccountLimit: ls.MaxNumRecentTxsPerAccountLimit(), MaxTxsPerBlockLimit: ls.MaxTxsPerBlockLimit(), } diff --git a/internal/configs/sharding/mainnet.go b/internal/configs/sharding/mainnet.go index e6999b083..a8cb1fd93 100644 --- a/internal/configs/sharding/mainnet.go +++ b/internal/configs/sharding/mainnet.go @@ -13,7 +13,7 @@ const ( mainnetV1Epoch = 1 mainnetV2Epoch = 5 - mainnetMaxTxAmountLimit = 1e3 // unit is in One + mainnetMaxTxAmountNanoLimit = 1e3 // unit is in One mainnetMaxNumRecentTxsPerAccountLimit = 10 mainnetMaxTxsPerBlockLimit = 8000 ) @@ -62,8 +62,8 @@ func (ms mainnetSchedule) IsLastBlock(blockNum uint64) bool { } } -func (ms mainnetSchedule) MaxTxAmountLimit() *big.Int { - amountBigInt := big.NewInt(int64(mainnetMaxTxAmountLimit * denominations.Nano)) +func (ms mainnetSchedule) MaxTxAmountNanoLimit() *big.Int { + amountBigInt := big.NewInt(mainnetMaxTxAmountNanoLimit) amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) return amountBigInt } @@ -78,7 +78,7 @@ func (ms mainnetSchedule) MaxTxsPerBlockLimit() int { func (ms mainnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: ms.MaxTxAmountLimit(), + MaxTxAmountNanoLimit: ms.MaxTxAmountNanoLimit(), MaxNumRecentTxsPerAccountLimit: ms.MaxNumRecentTxsPerAccountLimit(), MaxTxsPerBlockLimit: ms.MaxTxsPerBlockLimit(), } diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index 11fa24f7b..c361d0aea 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -23,7 +23,7 @@ type Schedule interface { IsLastBlock(blockNum uint64) bool // Max amount limit for a valid transaction - MaxTxAmountLimit() *big.Int + MaxTxAmountNanoLimit() *big.Int // Max number of transactions of a particular account per block level MaxNumRecentTxsPerAccountLimit() uint64 @@ -85,7 +85,7 @@ func (result TxThrottleFlag) String() string { // TxsThrottleConfig contains configuration for throttling pending transactions per node block type TxsThrottleConfig struct { // Max amount limit for a valid transaction - MaxTxAmountLimit *big.Int + MaxTxAmountNanoLimit *big.Int // Max number of transactions of a particular account for the past hour MaxNumRecentTxsPerAccountLimit uint64 diff --git a/internal/configs/sharding/testnet.go b/internal/configs/sharding/testnet.go index 5cc544aa5..787a3febe 100644 --- a/internal/configs/sharding/testnet.go +++ b/internal/configs/sharding/testnet.go @@ -20,7 +20,7 @@ const ( testnetEpochBlock1 = 78 threeOne = 111 - testnetMaxTxAmountLimit = 1e3 // unit is in One + testnetMaxTxAmountNanoLimit = 1e3 // unit is in One testnetMaxNumRecentTxsPerAccountLimit = 10 testnetMaxTxsPerBlockLimit = 8000 ) @@ -63,8 +63,8 @@ func (ts testnetSchedule) IsLastBlock(blockNum uint64) bool { } } -func (ts testnetSchedule) MaxTxAmountLimit() *big.Int { - amountBigInt := big.NewInt(int64(testnetMaxTxAmountLimit * denominations.Nano)) +func (ts testnetSchedule) MaxTxAmountNanoLimit() *big.Int { + amountBigInt := big.NewInt(testnetMaxTxAmountNanoLimit) amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) return amountBigInt } @@ -79,7 +79,7 @@ func (ts testnetSchedule) MaxTxsPerBlockLimit() int { func (ts testnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountLimit: ts.MaxTxAmountLimit(), + MaxTxAmountNanoLimit: ts.MaxTxAmountNanoLimit(), MaxNumRecentTxsPerAccountLimit: ts.MaxNumRecentTxsPerAccountLimit(), MaxTxsPerBlockLimit: ts.MaxTxsPerBlockLimit(), } diff --git a/node/node.go b/node/node.go index 030abceb2..6fb042c23 100644 --- a/node/node.go +++ b/node/node.go @@ -271,8 +271,7 @@ func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Tran node.pendingTransactions = unselected node.reducePendingTransactions() - utils.GetLogInstance().Info( - "msg", "Selecting Transactions", + utils.GetLogInstance().Info("Selecting Transactions", "newBlockNum", newBlockNum, "remainPending", len(node.pendingTransactions), "invalidDiscarded", len(invalid)) @@ -506,17 +505,17 @@ func (node *Node) initNodeConfiguration() (service.NodeConfig, chan p2p.Peer) { var err error node.shardGroupReceiver, err = node.host.GroupReceiver(node.NodeConfig.GetShardGroupID()) if err != nil { - utils.GetLogInstance().Error("Failed to create shard receiver", "msg", err) + utils.GetLogInstance().Error("Failed to create shard receiver", "err", err) } node.globalGroupReceiver, err = node.host.GroupReceiver(p2p.GroupIDBeaconClient) if err != nil { - utils.GetLogInstance().Error("Failed to create global receiver", "msg", err) + utils.GetLogInstance().Error("Failed to create global receiver", "err", err) } node.clientReceiver, err = node.host.GroupReceiver(node.NodeConfig.GetClientGroupID()) if err != nil { - utils.GetLogInstance().Error("Failed to create client receiver", "msg", err) + utils.GetLogInstance().Error("Failed to create client receiver", "err", err) } return nodeConfig, chanPeer } diff --git a/node/worker/worker.go b/node/worker/worker.go index 14e31ebe0..1e08da49f 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -59,24 +59,25 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R var sender common.Address msg, err := tx.AsMessage(s) if err != nil { - utils.GetLogInstance().Error("Error when parsing tx into message", "msg", err) + utils.GetLogInstance().Error("Error when parsing tx into message", + "tx Id", tx.Hash().Hex(), "err", err) } else { sender = msg.From() } // already selected max num txs - if len(selected) > (*txsThrottleConfig).MaxTxsPerBlockLimit { - utils.GetLogInstance().Info( - "msg", "Throttling tx with max txs per block limit", + if len(selected) > txsThrottleConfig.MaxTxsPerBlockLimit { + utils.GetLogInstance().Info("Throttling tx with max txs per block limit", + "tx Id", tx.Hash().Hex(), "MaxTxsPerBlockLimit", txsThrottleConfig.MaxTxsPerBlockLimit) return sender, shardingconfig.TxUnselect } // throttle a single sender sending too many transactions in one block - if (txsThrottleConfig.MaxTxAmountLimit).Cmp(tx.Value()) < 0 { - utils.GetLogInstance().Info( - "msg", "Throttling tx with max amount limit", - "MaxTxAmountLimit", txsThrottleConfig.MaxTxAmountLimit.Uint64(), + if txsThrottleConfig.MaxTxAmountNanoLimit.Cmp(tx.Value()) < 0 { + utils.GetLogInstance().Info("Throttling tx with max amount limit", + "tx Id", tx.Hash().Hex(), + "MaxTxAmountNanoLimit", txsThrottleConfig.MaxTxAmountNanoLimit.Uint64(), "Tx amount", tx.Value().Uint64()) return sender, shardingconfig.TxInvalid } @@ -87,8 +88,8 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R numTxsPastHour += blockTxsCounts[sender] } if numTxsPastHour >= txsThrottleConfig.MaxNumRecentTxsPerAccountLimit { - utils.GetLogInstance().Info( - "msg", "Throttling tx with max txs per account in a single block limit", + utils.GetLogInstance().Info("Throttling tx with max txs per account in a single block limit", + "tx Id", tx.Hash().Hex(), "MaxNumRecentTxsPerAccountLimit", txsThrottleConfig.MaxNumRecentTxsPerAccountLimit) return sender, shardingconfig.TxUnselect } @@ -133,8 +134,7 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra // log invalid or unselected txs if flag == shardingconfig.TxUnselect || flag == shardingconfig.TxInvalid { - utils.GetLogInstance().Info( - "msg", "Transaction Throttle flag", + utils.GetLogInstance().Info("Transaction Throttle flag", "Transaction Id", tx.Hash().Hex(), "txThrottleFlag", flag.String()) } From e37f3ed9660f01d5293265c12b2e6f14002d5727 Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 12:05:16 -0700 Subject: [PATCH 11/20] revert comparing by nano. compare max limit on tx amount with one --- cmd/client/wallet/main.go | 2 +- internal/configs/sharding/fixedschedule.go | 8 ++++---- internal/configs/sharding/localnet.go | 10 +++++----- internal/configs/sharding/mainnet.go | 10 +++++----- internal/configs/sharding/shardingconfig.go | 10 ++++++---- internal/configs/sharding/testnet.go | 10 +++++----- node/worker/worker.go | 4 ++-- 7 files changed, 28 insertions(+), 26 deletions(-) diff --git a/cmd/client/wallet/main.go b/cmd/client/wallet/main.go index 0cae37f95..3c86ffd2f 100644 --- a/cmd/client/wallet/main.go +++ b/cmd/client/wallet/main.go @@ -896,7 +896,7 @@ func submitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uin fmt.Printf("Error in SubmitTransaction: %v\n", err) return err } - fmt.Printf("Transaction Id for shard %d submitted: %s\n", int(shardID), tx.Hash().Hex()) + fmt.Printf("Transaction Id for shard %d: %s\n", int(shardID), tx.Hash().Hex()) // FIXME (leo): how to we know the tx was successful sent to the network // this is a hacky way to wait for sometime time.Sleep(3 * time.Second) diff --git a/internal/configs/sharding/fixedschedule.go b/internal/configs/sharding/fixedschedule.go index 74969e0ff..f308bed67 100644 --- a/internal/configs/sharding/fixedschedule.go +++ b/internal/configs/sharding/fixedschedule.go @@ -34,9 +34,9 @@ func (s fixedSchedule) IsLastBlock(blockNum uint64) bool { return blockNum%blocks == blocks-1 } -func (s fixedSchedule) MaxTxAmountNanoLimit() *big.Int { - amountBigInt := big.NewInt(mainnetMaxTxAmountNanoLimit) - amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) +func (s fixedSchedule) MaxTxAmountLimit() *big.Int { + amountBigInt := big.NewInt(mainnetMaxTxAmountLimit) + amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.One)) return amountBigInt } @@ -50,7 +50,7 @@ func (s fixedSchedule) MaxTxsPerBlockLimit() int { func (s fixedSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountNanoLimit: s.MaxTxAmountNanoLimit(), + MaxTxAmountLimit: s.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: s.MaxNumRecentTxsPerAccountLimit(), MaxTxsPerBlockLimit: s.MaxTxsPerBlockLimit(), } diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index 930fec25d..b3db864ce 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -20,7 +20,7 @@ const ( localnetEpochBlock1 = 20 twoOne = 5 - localnetMaxTxAmountNanoLimit = 1e2 // unit is in One + localnetMaxTxAmountLimit = 1e2 // unit is in One localnetMaxNumRecentTxsPerAccountLimit = 2 localnetMaxTxsPerBlockLimit = 8000 ) @@ -62,9 +62,9 @@ func (ls localnetSchedule) IsLastBlock(blockNum uint64) bool { } } -func (ls localnetSchedule) MaxTxAmountNanoLimit() *big.Int { - amountBigInt := big.NewInt(localnetMaxTxAmountNanoLimit) - amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) +func (ls localnetSchedule) MaxTxAmountLimit() *big.Int { + amountBigInt := big.NewInt(localnetMaxTxAmountLimit) + amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.One)) return amountBigInt } @@ -78,7 +78,7 @@ func (ls localnetSchedule) MaxTxsPerBlockLimit() int { func (ls localnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountNanoLimit: ls.MaxTxAmountNanoLimit(), + MaxTxAmountLimit: ls.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: ls.MaxNumRecentTxsPerAccountLimit(), MaxTxsPerBlockLimit: ls.MaxTxsPerBlockLimit(), } diff --git a/internal/configs/sharding/mainnet.go b/internal/configs/sharding/mainnet.go index a8cb1fd93..d441b1d52 100644 --- a/internal/configs/sharding/mainnet.go +++ b/internal/configs/sharding/mainnet.go @@ -13,7 +13,7 @@ const ( mainnetV1Epoch = 1 mainnetV2Epoch = 5 - mainnetMaxTxAmountNanoLimit = 1e3 // unit is in One + mainnetMaxTxAmountLimit = 1e3 // unit is in One mainnetMaxNumRecentTxsPerAccountLimit = 10 mainnetMaxTxsPerBlockLimit = 8000 ) @@ -62,9 +62,9 @@ func (ms mainnetSchedule) IsLastBlock(blockNum uint64) bool { } } -func (ms mainnetSchedule) MaxTxAmountNanoLimit() *big.Int { - amountBigInt := big.NewInt(mainnetMaxTxAmountNanoLimit) - amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) +func (ms mainnetSchedule) MaxTxAmountLimit() *big.Int { + amountBigInt := big.NewInt(mainnetMaxTxAmountLimit) + amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.One)) return amountBigInt } @@ -78,7 +78,7 @@ func (ms mainnetSchedule) MaxTxsPerBlockLimit() int { func (ms mainnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountNanoLimit: ms.MaxTxAmountNanoLimit(), + MaxTxAmountLimit: ms.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: ms.MaxNumRecentTxsPerAccountLimit(), MaxTxsPerBlockLimit: ms.MaxTxsPerBlockLimit(), } diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index c361d0aea..9edbb254b 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -23,7 +23,7 @@ type Schedule interface { IsLastBlock(blockNum uint64) bool // Max amount limit for a valid transaction - MaxTxAmountNanoLimit() *big.Int + MaxTxAmountLimit() *big.Int // Max number of transactions of a particular account per block level MaxNumRecentTxsPerAccountLimit() uint64 @@ -60,10 +60,12 @@ type Instance interface { ReshardingEpoch() []*big.Int } -// TxThrottleFlag indicates the throttling flag for a particular transaction +// TxThrottleFlag is the throttling flag for each transaction +// Refer below enum declaration for more context. type TxThrottleFlag int -// Enum for different TxThrottleFlag +// TxThrottleFlag is determined per transaction +// during the new block proposal and pending transactions throttling const ( TxSelect TxThrottleFlag = iota TxUnselect @@ -85,7 +87,7 @@ func (result TxThrottleFlag) String() string { // TxsThrottleConfig contains configuration for throttling pending transactions per node block type TxsThrottleConfig struct { // Max amount limit for a valid transaction - MaxTxAmountNanoLimit *big.Int + MaxTxAmountLimit *big.Int // Max number of transactions of a particular account for the past hour MaxNumRecentTxsPerAccountLimit uint64 diff --git a/internal/configs/sharding/testnet.go b/internal/configs/sharding/testnet.go index 787a3febe..1e478e68f 100644 --- a/internal/configs/sharding/testnet.go +++ b/internal/configs/sharding/testnet.go @@ -20,7 +20,7 @@ const ( testnetEpochBlock1 = 78 threeOne = 111 - testnetMaxTxAmountNanoLimit = 1e3 // unit is in One + testnetMaxTxAmountLimit = 1e3 // unit is in One testnetMaxNumRecentTxsPerAccountLimit = 10 testnetMaxTxsPerBlockLimit = 8000 ) @@ -63,9 +63,9 @@ func (ts testnetSchedule) IsLastBlock(blockNum uint64) bool { } } -func (ts testnetSchedule) MaxTxAmountNanoLimit() *big.Int { - amountBigInt := big.NewInt(testnetMaxTxAmountNanoLimit) - amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.Nano)) +func (ts testnetSchedule) MaxTxAmountLimit() *big.Int { + amountBigInt := big.NewInt(testnetMaxTxAmountLimit) + amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(denominations.One)) return amountBigInt } @@ -79,7 +79,7 @@ func (ts testnetSchedule) MaxTxsPerBlockLimit() int { func (ts testnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ - MaxTxAmountNanoLimit: ts.MaxTxAmountNanoLimit(), + MaxTxAmountLimit: ts.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: ts.MaxNumRecentTxsPerAccountLimit(), MaxTxsPerBlockLimit: ts.MaxTxsPerBlockLimit(), } diff --git a/node/worker/worker.go b/node/worker/worker.go index 1e08da49f..220961486 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -74,10 +74,10 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R } // throttle a single sender sending too many transactions in one block - if txsThrottleConfig.MaxTxAmountNanoLimit.Cmp(tx.Value()) < 0 { + if tx.Value().Cmp(txsThrottleConfig.MaxTxAmountLimit) > 0 { utils.GetLogInstance().Info("Throttling tx with max amount limit", "tx Id", tx.Hash().Hex(), - "MaxTxAmountNanoLimit", txsThrottleConfig.MaxTxAmountNanoLimit.Uint64(), + "MaxTxAmountLimit", txsThrottleConfig.MaxTxAmountLimit.Uint64(), "Tx amount", tx.Value().Uint64()) return sender, shardingconfig.TxInvalid } From 0d79de61a2661087e95af515ecdf952b3bd1246e Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 12:13:07 -0700 Subject: [PATCH 12/20] added error handling for the case when msg was not able to extracted from tx during throttling tx --- node/worker/worker.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/node/worker/worker.go b/node/worker/worker.go index 220961486..7e5d62b52 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -128,7 +128,10 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra } else { selected = append(selected, tx) - recentTxsStats[newBlockNum][sender]++ + // handle the case when msg was not able to extracted from tx + if len(sender.String()) > 0 { + recentTxsStats[newBlockNum][sender]++ + } } } From 24a87fdcc3d970fd8ffb1b51bb48afee76036373 Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 13:17:22 -0700 Subject: [PATCH 13/20] enable transactions by addiontally removing network check --- node/node_newblock.go | 5 ----- node/worker/worker.go | 4 +++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/node/node_newblock.go b/node/node_newblock.go index c07174cb5..77bf8030f 100644 --- a/node/node_newblock.go +++ b/node/node_newblock.go @@ -67,11 +67,6 @@ func (node *Node) WaitForConsensusReadyv2(readySignal chan struct{}, stopChan ch viewID := node.Consensus.GetViewID() // add aggregated commit signatures from last block, except for the first two blocks - if err = node.Worker.UpdateCurrent(coinbase); err != nil { - utils.GetLogger().Debug("Failed updating worker's state", "Error", err) - continue - } - newBlock, err = node.Worker.Commit(sig, mask, viewID, coinbase) if err != nil { diff --git a/node/worker/worker.go b/node/worker/worker.go index 7e5d62b52..b4f1c1615 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -125,7 +125,9 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra if err != nil { w.current.state.RevertToSnapshot(snap) invalid = append(invalid, tx) - + utils.GetLogInstance().Error("Commit transaction error", + "Transaction Id", tx.Hash().Hex(), + "err", err) } else { selected = append(selected, tx) // handle the case when msg was not able to extracted from tx From dffe6652a792fcaf0c177f8d69da8eb15b9b1f5d Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 14:41:22 -0700 Subject: [PATCH 14/20] Renamed the prev MaxNumTxsPerBlockLimit to tx pool size limit and added another config value MaxNumTxsPerBlockLimit separately --- core/types/transaction.go | 2 ++ internal/configs/sharding/fixedschedule.go | 11 ++++++++--- internal/configs/sharding/localnet.go | 14 ++++++++++---- internal/configs/sharding/mainnet.go | 14 ++++++++++---- internal/configs/sharding/shardingconfig.go | 14 ++++++++++---- internal/configs/sharding/testnet.go | 14 ++++++++++---- node/node.go | 2 +- node/worker/worker.go | 16 +++++++++++++--- 8 files changed, 64 insertions(+), 23 deletions(-) diff --git a/core/types/transaction.go b/core/types/transaction.go index 609b83044..cb186a469 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -295,6 +295,8 @@ func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) { // Transactions is a Transaction slice type for basic sorting. type Transactions []*Transaction +// TODO: put these temp custom txs data structures into other places to keep Transaction type code clean. + // RecentTxsStats is a recent transactions stats map tracking stats like BlockTxsCounts. type RecentTxsStats map[uint64]BlockTxsCounts diff --git a/internal/configs/sharding/fixedschedule.go b/internal/configs/sharding/fixedschedule.go index f308bed67..db7f4057f 100644 --- a/internal/configs/sharding/fixedschedule.go +++ b/internal/configs/sharding/fixedschedule.go @@ -44,15 +44,20 @@ func (s fixedSchedule) MaxNumRecentTxsPerAccountLimit() uint64 { return mainnetMaxNumRecentTxsPerAccountLimit } -func (s fixedSchedule) MaxTxsPerBlockLimit() int { - return mainnetMaxTxsPerBlockLimit +func (s fixedSchedule) MaxTxPoolSizeLimit() int { + return mainnetMaxTxPoolSizeLimit +} + +func (s fixedSchedule) MaxNumTxsPerBlockLimit() int { + return mainnetMaxNumTxsPerBlockLimit } func (s fixedSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ MaxTxAmountLimit: s.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: s.MaxNumRecentTxsPerAccountLimit(), - MaxTxsPerBlockLimit: s.MaxTxsPerBlockLimit(), + MaxTxPoolSizeLimit: s.MaxTxPoolSizeLimit(), + MaxNumTxsPerBlockLimit: s.MaxNumTxsPerBlockLimit(), } } diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index b3db864ce..4416fa674 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -22,7 +22,8 @@ const ( localnetMaxTxAmountLimit = 1e2 // unit is in One localnetMaxNumRecentTxsPerAccountLimit = 2 - localnetMaxTxsPerBlockLimit = 8000 + localnetMaxTxPoolSizeLimit = 8000 + localnetMaxNumTxsPerBlockLimit = 1000 ) func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -72,15 +73,20 @@ func (ls localnetSchedule) MaxNumRecentTxsPerAccountLimit() uint64 { return localnetMaxNumRecentTxsPerAccountLimit } -func (ls localnetSchedule) MaxTxsPerBlockLimit() int { - return localnetMaxTxsPerBlockLimit +func (ls localnetSchedule) MaxTxPoolSizeLimit() int { + return localnetMaxTxPoolSizeLimit +} + +func (ls localnetSchedule) MaxNumTxsPerBlockLimit() int { + return localnetMaxNumTxsPerBlockLimit } func (ls localnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ MaxTxAmountLimit: ls.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: ls.MaxNumRecentTxsPerAccountLimit(), - MaxTxsPerBlockLimit: ls.MaxTxsPerBlockLimit(), + MaxTxPoolSizeLimit: ls.MaxTxPoolSizeLimit(), + MaxNumTxsPerBlockLimit: ls.MaxNumTxsPerBlockLimit(), } } diff --git a/internal/configs/sharding/mainnet.go b/internal/configs/sharding/mainnet.go index d441b1d52..4c86eac8b 100644 --- a/internal/configs/sharding/mainnet.go +++ b/internal/configs/sharding/mainnet.go @@ -15,7 +15,8 @@ const ( mainnetMaxTxAmountLimit = 1e3 // unit is in One mainnetMaxNumRecentTxsPerAccountLimit = 10 - mainnetMaxTxsPerBlockLimit = 8000 + mainnetMaxTxPoolSizeLimit = 8000 + mainnetMaxNumTxsPerBlockLimit = 1000 ) // MainnetSchedule is the mainnet sharding configuration schedule. @@ -72,15 +73,20 @@ func (ms mainnetSchedule) MaxNumRecentTxsPerAccountLimit() uint64 { return mainnetMaxNumRecentTxsPerAccountLimit } -func (ms mainnetSchedule) MaxTxsPerBlockLimit() int { - return mainnetMaxTxsPerBlockLimit +func (ms mainnetSchedule) MaxTxPoolSizeLimit() int { + return mainnetMaxTxPoolSizeLimit +} + +func (ms mainnetSchedule) MaxNumTxsPerBlockLimit() int { + return mainnetMaxNumTxsPerBlockLimit } func (ms mainnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ MaxTxAmountLimit: ms.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: ms.MaxNumRecentTxsPerAccountLimit(), - MaxTxsPerBlockLimit: ms.MaxTxsPerBlockLimit(), + MaxTxPoolSizeLimit: ms.MaxTxPoolSizeLimit(), + MaxNumTxsPerBlockLimit: ms.MaxNumTxsPerBlockLimit(), } } diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index 9edbb254b..1b6feb2cf 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -28,8 +28,11 @@ type Schedule interface { // Max number of transactions of a particular account per block level MaxNumRecentTxsPerAccountLimit() uint64 - // Max total number of transactions in a block - MaxTxsPerBlockLimit() int + // Max total number of transactions allowed as pending transactions in transaction pool + MaxTxPoolSizeLimit() int + + // Max total number of transactions allowed to be processed per block + MaxNumTxsPerBlockLimit() int // configuration for throttling pending transactions TxsThrottleConfig() *TxsThrottleConfig @@ -92,6 +95,9 @@ type TxsThrottleConfig struct { // Max number of transactions of a particular account for the past hour MaxNumRecentTxsPerAccountLimit uint64 - // Max total number of transactions in a block - MaxTxsPerBlockLimit int + // Max total number of transactions allowed as pending transactions in transaction pool + MaxTxPoolSizeLimit int + + // Max total number of transactions allowed to be processed per block + MaxNumTxsPerBlockLimit int } diff --git a/internal/configs/sharding/testnet.go b/internal/configs/sharding/testnet.go index 1e478e68f..a472bb417 100644 --- a/internal/configs/sharding/testnet.go +++ b/internal/configs/sharding/testnet.go @@ -22,7 +22,8 @@ const ( testnetMaxTxAmountLimit = 1e3 // unit is in One testnetMaxNumRecentTxsPerAccountLimit = 10 - testnetMaxTxsPerBlockLimit = 8000 + testnetMaxTxPoolSizeLimit = 8000 + testnetMaxNumTxsPerBlockLimit = 1000 ) func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -73,15 +74,20 @@ func (ts testnetSchedule) MaxNumRecentTxsPerAccountLimit() uint64 { return testnetMaxNumRecentTxsPerAccountLimit } -func (ts testnetSchedule) MaxTxsPerBlockLimit() int { - return testnetMaxTxsPerBlockLimit +func (ts testnetSchedule) MaxTxPoolSizeLimit() int { + return testnetMaxTxPoolSizeLimit +} + +func (ts testnetSchedule) MaxNumTxsPerBlockLimit() int { + return testnetMaxNumTxsPerBlockLimit } func (ts testnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ MaxTxAmountLimit: ts.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: ts.MaxNumRecentTxsPerAccountLimit(), - MaxTxsPerBlockLimit: ts.MaxTxsPerBlockLimit(), + MaxTxPoolSizeLimit: ts.MaxTxPoolSizeLimit(), + MaxNumTxsPerBlockLimit: ts.MaxNumTxsPerBlockLimit(), } } diff --git a/node/node.go b/node/node.go index 6fb042c23..32e4df98b 100644 --- a/node/node.go +++ b/node/node.go @@ -226,7 +226,7 @@ func (node *Node) Beaconchain() *core.BlockChain { } func (node *Node) reducePendingTransactions() { - txPoolLimit := core.ShardingSchedule.MaxTxsPerBlockLimit() + txPoolLimit := core.ShardingSchedule.MaxTxPoolSizeLimit() curLen := len(node.pendingTransactions) // If length of pendingTransactions is greater than TxPoolLimit then by greedy take the TxPoolLimit recent transactions. diff --git a/node/worker/worker.go b/node/worker/worker.go index b4f1c1615..76daaf9d6 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -66,10 +66,10 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R } // already selected max num txs - if len(selected) > txsThrottleConfig.MaxTxsPerBlockLimit { - utils.GetLogInstance().Info("Throttling tx with max txs per block limit", + if len(selected) > txsThrottleConfig.MaxNumTxsPerBlockLimit { + utils.GetLogInstance().Info("Throttling tx with max num txs per block limit", "tx Id", tx.Hash().Hex(), - "MaxTxsPerBlockLimit", txsThrottleConfig.MaxTxsPerBlockLimit) + "MaxNumTxsPerBlockLimit", txsThrottleConfig.MaxNumTxsPerBlockLimit) return sender, shardingconfig.TxUnselect } @@ -143,7 +143,17 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra "Transaction Id", tx.Hash().Hex(), "txThrottleFlag", flag.String()) } + + utils.GetLogInstance().Info("Transaction gas limit info", + "Transaction Id", tx.Hash().Hex(), + "tx gas limit", tx.Gas()) } + + utils.GetLogInstance().Info("Block gas limit and usage info", + "newBlockNum", newBlockNum, + "block gas limit", w.current.header.GasLimit, + "block gas used", w.current.header.GasUsed) + return selected, unselected, invalid } From 8bd49d7736f6e6768c76d9e02dc15d44f25bb193 Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Fri, 9 Aug 2019 16:30:21 -0700 Subject: [PATCH 15/20] fix unit test that failed travis --- node/node.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/node.go b/node/node.go index 32e4df98b..f38edc3c7 100644 --- a/node/node.go +++ b/node/node.go @@ -257,7 +257,9 @@ func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Tran node.pendingTxMutex.Lock() // update recentTxsStats and initiailize for the new block - newBlockNum := node.Consensus.ChainReader.CurrentHeader().Number.Uint64() + 1 + + // the next block number to be added in consensus protocol, which is always one more than current chain header block + newBlockNum := node.Blockchain().CurrentBlock().NumberU64() + 1 for blockNum := range node.recentTxsStats { blockNumHourAgo := (time.Hour / time.Second) / node.BlockPeriod if blockNum < node.Consensus.ChainReader.CurrentHeader().Number.Uint64()-uint64(blockNumHourAgo) { From bf07063a2e24d12e4265d3e05fbcefca8b68d67c Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Mon, 12 Aug 2019 18:14:02 -0700 Subject: [PATCH 16/20] fix recentTxsCounts map data clean up bug --- core/types/transaction.go | 16 +++++++--------- node/node.go | 22 +++++++++++++--------- node/worker/worker.go | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/core/types/transaction.go b/core/types/transaction.go index cb186a469..6657b5342 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -295,15 +295,6 @@ func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) { // Transactions is a Transaction slice type for basic sorting. type Transactions []*Transaction -// TODO: put these temp custom txs data structures into other places to keep Transaction type code clean. - -// RecentTxsStats is a recent transactions stats map tracking stats like BlockTxsCounts. -type RecentTxsStats map[uint64]BlockTxsCounts - -// BlockTxsCounts is a transactions counts map of -// the number of transactions made by each account in a block on this node. -type BlockTxsCounts map[common.Address]uint64 - // Len returns the length of s. func (s Transactions) Len() int { return len(s) } @@ -494,3 +485,10 @@ func (m Message) Data() []byte { func (m Message) CheckNonce() bool { return m.checkNonce } + +// RecentTxsStats is a recent transactions stats map tracking stats like BlockTxsCounts. +type RecentTxsStats map[uint64]BlockTxsCounts + +// BlockTxsCounts is a transactions counts map of +// the number of transactions made by each account in a block on this node. +type BlockTxsCounts map[common.Address]uint64 diff --git a/node/node.go b/node/node.go index f38edc3c7..62d665b63 100644 --- a/node/node.go +++ b/node/node.go @@ -90,10 +90,8 @@ type Node struct { BlockChannel chan *types.Block // The channel to send newly proposed blocks ConfirmedBlockChannel chan *types.Block // The channel to send confirmed blocks BeaconBlockChannel chan *types.Block // The channel to send beacon blocks for non-beaconchain nodes - pendingTransactions types.Transactions // All the transactions received but not yet processed for Consensus - pendingTxMutex sync.Mutex - recentTxsStats types.RecentTxsStats - DRand *drand.DRand // The instance for distributed randomness protocol + + DRand *drand.DRand // The instance for distributed randomness protocol // Shard databases shardChains shardchain.Collection @@ -112,7 +110,12 @@ type Node struct { // BeaconNeighbors store only neighbor nodes in the beacon chain shard BeaconNeighbors sync.Map // All the neighbor nodes, key is the sha256 of Peer IP/Port, value is the p2p.Peer - TxPool *core.TxPool + TxPool *core.TxPool // TODO migrate to TxPool from pendingTransactions list below + + pendingTransactions types.Transactions // All the transactions received but not yet processed for Consensus + pendingTxMutex sync.Mutex + recentTxsStats types.RecentTxsStats + Worker *worker.Worker BeaconWorker *worker.Worker // worker for beacon chain @@ -256,13 +259,14 @@ func (node *Node) AddPendingTransaction(newTx *types.Transaction) { func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Transactions { node.pendingTxMutex.Lock() - // update recentTxsStats and initiailize for the new block - // the next block number to be added in consensus protocol, which is always one more than current chain header block newBlockNum := node.Blockchain().CurrentBlock().NumberU64() + 1 + + // remove old (currently > 1 hr) blockNum keys from recentTxsStats and initiailize for the new block for blockNum := range node.recentTxsStats { - blockNumHourAgo := (time.Hour / time.Second) / node.BlockPeriod - if blockNum < node.Consensus.ChainReader.CurrentHeader().Number.Uint64()-uint64(blockNumHourAgo) { + blockNumHourAgo := uint64(time.Hour / node.BlockPeriod) + + if blockNumHourAgo < newBlockNum-blockNum { delete(node.recentTxsStats, blockNum) } } diff --git a/node/worker/worker.go b/node/worker/worker.go index 76daaf9d6..78468993f 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -91,7 +91,7 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R utils.GetLogInstance().Info("Throttling tx with max txs per account in a single block limit", "tx Id", tx.Hash().Hex(), "MaxNumRecentTxsPerAccountLimit", txsThrottleConfig.MaxNumRecentTxsPerAccountLimit) - return sender, shardingconfig.TxUnselect + return sender, shardingconfig.TxInvalid } return sender, shardingconfig.TxSelect From abd670639bff2615c08c560a7d9cdea1001bba76 Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Mon, 12 Aug 2019 22:45:12 -0700 Subject: [PATCH 17/20] wallet stress_test_script v.0 for stress testing token transfer --- cmd/client/wallet/main.go | 7 +- cmd/client/wallet_stress_test/README.md | 1 + .../generated_wallet.ini.go | 60 +++ cmd/client/wallet_stress_test/main.go | 437 ++++++++++++++++++ internal/configs/sharding/fixedschedule.go | 6 + internal/configs/sharding/localnet.go | 7 + internal/configs/sharding/mainnet.go | 9 +- internal/configs/sharding/shardingconfig.go | 7 + internal/configs/sharding/testnet.go | 9 +- node/node.go | 8 +- node/worker/worker.go | 1 + scripts/go_executable_build.sh | 1 + 12 files changed, 547 insertions(+), 6 deletions(-) create mode 100644 cmd/client/wallet_stress_test/README.md create mode 100644 cmd/client/wallet_stress_test/generated_wallet.ini.go create mode 100644 cmd/client/wallet_stress_test/main.go diff --git a/cmd/client/wallet/main.go b/cmd/client/wallet/main.go index 3c86ffd2f..c21e4abaf 100644 --- a/cmd/client/wallet/main.go +++ b/cmd/client/wallet/main.go @@ -91,6 +91,7 @@ var ( transferSenderPtr = transferCommand.String("from", "0", "Specify the sender account address or index") transferReceiverPtr = transferCommand.String("to", "", "Specify the receiver account") transferAmountPtr = transferCommand.Float64("amount", 0, "Specify the amount to transfer") + transferGasPricePtr = transferCommand.Uint64("gasPrice", 0, "Specify the gas price amount. Unit is Nano.") transferShardIDPtr = transferCommand.Int("shardID", 0, "Specify the shard ID for the transfer") transferInputDataPtr = transferCommand.String("inputData", "", "Base64-encoded input data to embed in the transaction") transferSenderPassPtr = transferCommand.String("pass", "", "Passphrase of the sender's private key") @@ -651,6 +652,7 @@ func processTransferCommand() { sender := *transferSenderPtr receiver := *transferReceiverPtr amount := *transferAmountPtr + gasPrice := *transferGasPricePtr shardID := *transferShardIDPtr base64InputData := *transferInputDataPtr senderPass := *transferSenderPassPtr @@ -708,9 +710,12 @@ func processTransferCommand() { return } + gasPriceBigInt := big.NewInt(int64(gasPrice)) + gasPriceBigInt = gasPriceBigInt.Mul(gasPriceBigInt, big.NewInt(denominations.Nano)) + tx := types.NewTransaction( state.nonce, receiverAddress, uint32(shardID), amountBigInt, - gas, nil, inputData) + gas, gasPriceBigInt, inputData) account, err := ks.Find(accounts.Account{Address: senderAddress}) if err != nil { diff --git a/cmd/client/wallet_stress_test/README.md b/cmd/client/wallet_stress_test/README.md new file mode 100644 index 000000000..159d16be7 --- /dev/null +++ b/cmd/client/wallet_stress_test/README.md @@ -0,0 +1 @@ +The wallet program is the demo wallet which talks to Harmony devnet for various kinds of operations. For detail, please compile and execute ./bin/wallet. \ No newline at end of file diff --git a/cmd/client/wallet_stress_test/generated_wallet.ini.go b/cmd/client/wallet_stress_test/generated_wallet.ini.go new file mode 100644 index 000000000..b1ed56eff --- /dev/null +++ b/cmd/client/wallet_stress_test/generated_wallet.ini.go @@ -0,0 +1,60 @@ +package main + +const ( + defaultWalletIni = `[default] +bootnode = /ip4/100.26.90.187/tcp/9874/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv +bootnode = /ip4/54.213.43.194/tcp/9874/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 +shards = 4 + +[default.shard0.rpc] +rpc = l0.t.hmny.io:14555 +rpc = s0.t.hmny.io:14555 + +[default.shard1.rpc] +rpc = l1.t.hmny.io:14555 +rpc = s1.t.hmny.io:14555 + +[default.shard2.rpc] +rpc = l2.t.hmny.io:14555 +rpc = s2.t.hmny.io:14555 + +[default.shard3.rpc] +rpc = l3.t.hmny.io:14555 +rpc = s3.t.hmny.io:14555 + +[local] +bootnode = /ip4/127.0.0.1/tcp/19876/p2p/Qmc1V6W7BwX8Ugb42Ti8RnXF1rY5PF7nnZ6bKBryCgi6cv +shards = 2 + +[local.shard0.rpc] +rpc = 127.0.0.1:14555 +rpc = 127.0.0.1:14557 +rpc = 127.0.0.1:14559 + +[local.shard1.rpc] +rpc = 127.0.0.1:14556 +rpc = 127.0.0.1:14558 +rpc = 127.0.0.1:14560 + +[devnet] +bootnode = /ip4/100.26.90.187/tcp/9871/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv +bootnode = /ip4/54.213.43.194/tcp/9871/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj +shards = 4 + +[devnet.shard0.rpc] +rpc = l0.t1.hmny.io:14555 +rpc = s0.t1.hmny.io:14555 + +[devnet.shard1.rpc] +rpc = l1.t1.hmny.io:14555 +rpc = s1.t1.hmny.io:14555 + +[devnet.shard2.rpc] +rpc = l2.t1.hmny.io:14555 +rpc = s2.t1.hmny.io:14555 + +[devnet.shard3.rpc] +rpc = l3.t1.hmny.io:14555 +rpc = s3.t1.hmny.io:14555 +` +) diff --git a/cmd/client/wallet_stress_test/main.go b/cmd/client/wallet_stress_test/main.go new file mode 100644 index 000000000..a03aa73de --- /dev/null +++ b/cmd/client/wallet_stress_test/main.go @@ -0,0 +1,437 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "math/big" + "math/rand" + "os" + "path" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/harmony-one/harmony/accounts" + "github.com/harmony-one/harmony/accounts/keystore" + "github.com/harmony-one/harmony/api/client" + clientService "github.com/harmony-one/harmony/api/client/service" + proto_node "github.com/harmony-one/harmony/api/proto/node" + "github.com/harmony-one/harmony/common/denominations" + "github.com/harmony-one/harmony/core" + "github.com/harmony-one/harmony/core/types" + common2 "github.com/harmony-one/harmony/internal/common" + nodeconfig "github.com/harmony-one/harmony/internal/configs/node" + "github.com/harmony-one/harmony/internal/ctxerror" + "github.com/harmony-one/harmony/internal/shardchain" + "github.com/harmony-one/harmony/internal/utils" + "github.com/harmony-one/harmony/node" + "github.com/harmony-one/harmony/p2p" + p2p_host "github.com/harmony-one/harmony/p2p/host" + "github.com/harmony-one/harmony/p2p/p2pimpl" +) + +var ( + version string + builtBy string + builtAt string + commit string +) + +func printVersion(me string) { + fmt.Fprintf(os.Stderr, "Harmony (C) 2019. %v, version %v-%v (%v %v)\n", path.Base(me), version, commit, builtBy, builtAt) + os.Exit(0) +} + +// AccountState includes the balance and nonce of an account +type AccountState struct { + balance *big.Int + nonce uint64 +} + +const ( + rpcRetry = 3 + defaultConfigFile = ".hmy/wallet.ini" + defaultProfile = "default" + keystoreDir = ".hmy/keystore" +) + +var ( + // Transfer subcommands + transferCommand = flag.NewFlagSet("transfer", flag.ExitOnError) + transferSenderPtr = transferCommand.String("from", "0", "Specify the sender account address or index") + transferReceiverPtr = transferCommand.String("to", "", "Specify the receiver account") + transferAmountPtr = transferCommand.Float64("amount", 0, "Specify the amount to transfer") + transferGasPricePtr = transferCommand.Uint64("gasPrice", 0, "Specify the gas price amount. Unit is Nano.") + transferShardIDPtr = transferCommand.Int("shardID", 0, "Specify the shard ID for the transfer") + transferInputDataPtr = transferCommand.String("inputData", "", "Base64-encoded input data to embed in the transaction") + transferSenderPassPtr = transferCommand.String("pass", "", "Passphrase of the sender's private key") +) + +var ( + walletProfile *utils.WalletProfile + ks *keystore.KeyStore +) + +// setupLog setup log for verbose output +func setupLog() { + // enable logging for wallet + h := log.StreamHandler(os.Stdout, log.TerminalFormat(true)) + log.Root().SetHandler(h) +} + +// The main wallet program entrance. Note the this wallet program is for demo-purpose only. It does not implement +// the secure storage of keys. +func main() { + rand.Seed(int64(time.Now().Nanosecond())) + + // Verify that a subcommand has been provided + // os.Arg[0] is the main command + // os.Arg[1] will be the subcommand + if len(os.Args) < 2 { + fmt.Println("Usage:") + fmt.Println(" wallet -p profile ") + fmt.Println(" -p profile - Specify the profile of the wallet, either testnet/devnet or others configured. Default is: testnet") + fmt.Println(" The profile is in file:", defaultConfigFile) + fmt.Println() + fmt.Println("Actions:") + fmt.Println(" 1. stressTest - Stress test transactions with corner cases.") + os.Exit(1) + } + +ARG: + for { + lastArg := os.Args[len(os.Args)-1] + switch lastArg { + case "--verbose": + setupLog() + os.Args = os.Args[:len(os.Args)-1] + default: + break ARG + } + } + + var profile string + if os.Args[1] == "-p" { + profile = os.Args[2] + os.Args = os.Args[2:] + } else { + profile = defaultProfile + } + if len(os.Args) == 1 { + fmt.Println("Missing action") + flag.PrintDefaults() + os.Exit(1) + } + + // create new keystore backend + scryptN := keystore.StandardScryptN + scryptP := keystore.StandardScryptP + ks = keystore.NewKeyStore(keystoreDir, scryptN, scryptP) + + // Switch on the subcommand + switch os.Args[1] { + case "-version": + printVersion(os.Args[0]) + case "stressTest": + readProfile(profile) + processStressTestCommand() + default: + fmt.Printf("Unknown action: %s\n", os.Args[1]) + flag.PrintDefaults() + os.Exit(1) + } +} + +//go:generate go run ../../../scripts/wallet_embed_ini_files.go + +func readProfile(profile string) { + fmt.Printf("Using %s profile for wallet\n", profile) + + // try to load .hmy/wallet.ini from filesystem + // use default_wallet_ini if .hmy/wallet.ini doesn't exist + var err error + var iniBytes []byte + + iniBytes, err = ioutil.ReadFile(defaultConfigFile) + if err != nil { + log.Debug(fmt.Sprintf("%s doesn't exist, using default ini\n", defaultConfigFile)) + iniBytes = []byte(defaultWalletIni) + } + + walletProfile, err = utils.ReadWalletProfile(iniBytes, profile) + if err != nil { + fmt.Printf("Read wallet profile error: %v\nExiting ...\n", err) + os.Exit(2) + } +} + +// createWalletNode creates wallet server node. +func createWalletNode() *node.Node { + bootNodeAddrs, err := utils.StringsToAddrs(walletProfile.Bootnodes) + if err != nil { + panic(err) + } + utils.BootNodes = bootNodeAddrs + shardID := 0 + // dummy host for wallet + // TODO: potentially, too many dummy IP may flush out good IP address from our bootnode DHT + // we need to understand the impact to bootnode DHT with this dummy host ip added + self := p2p.Peer{IP: "127.0.0.1", Port: "6999"} + priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "6999") + host, err := p2pimpl.NewHost(&self, priKey) + if err != nil { + panic(err) + } + chainDBFactory := &shardchain.MemDBFactory{} + w := node.New(host, nil, chainDBFactory, false) + w.Client = client.NewClient(w.GetHost(), uint32(shardID)) + + w.NodeConfig.SetRole(nodeconfig.ClientNode) + w.ServiceManagerSetup() + w.RunServices() + return w +} + +// ./bin/wallet -p local transfer +// --from one1uyshu2jgv8w465yc8kkny36thlt2wvel89tcmg +// --to one1spshr72utf6rwxseaz339j09ed8p6f8ke370zj +// --amount 1 --shardID 1 + +func processStressTestCommand() { + /* + + Account 17: + Address: one1spshr72utf6rwxseaz339j09ed8p6f8ke370zj + Balance in Shard 0: x.xxx, nonce: 0 + Balance in Shard 1: 0.0000, nonce: 0 + Account 18: + Address: one1uyshu2jgv8w465yc8kkny36thlt2wvel89tcmg + Balance in Shard 0: 0.0000, nonce: 0 + Balance in Shard 1: x.xxx, nonce: 0 + + */ + + senderAddress := common2.ParseAddr("one1uyshu2jgv8w465yc8kkny36thlt2wvel89tcmg") + receiverAddress := common2.ParseAddr("one1spshr72utf6rwxseaz339j09ed8p6f8ke370zj") + shardID := 1 + + walletNode := createWalletNode() + + shardIDToAccountState := FetchBalance(senderAddress) + state := shardIDToAccountState[shardID] + + balance := state.balance + // amount 1/10th of the balance + amountBigInt := balance.Div(balance, big.NewInt(10)) + + // default inputData + data := make([]byte, 0) + + gasLimit, _ := core.IntrinsicGas(data, false, true) + + gasPrice := 0 + gasPriceBigInt := big.NewInt(int64(gasPrice)) + gasPriceBigInt = gasPriceBigInt.Mul(gasPriceBigInt, big.NewInt(denominations.Nano)) + + senderPass := "" + + for i := 0; i < 4; i++ { + currNonce := state.nonce + tx := types.NewTransaction( + currNonce, receiverAddress, uint32(shardID), amountBigInt, + gasLimit, gasPriceBigInt, data) + + account, _ := ks.Find(accounts.Account{Address: senderAddress}) + + ks.Unlock(account, senderPass) + + tx, _ = ks.SignTx(account, tx, nil) + + if err := submitTransaction(tx, walletNode, uint32(shardID)); err != nil { + fmt.Println(ctxerror.New("submitTransaction failed", + "tx", tx, "shardID", shardID).WithCause(err)) + } + + for retry := 0; retry < 10; retry++ { + accountStates := FetchBalance(senderAddress) + state = accountStates[shardID] + fmt.Println("state.nonce", state.nonce) + if state.nonce == currNonce+1 { + break + } + time.Sleep(3 * time.Second) + } + } + + fmt.Printf("Sender Account: %s:\n", common2.MustAddressToBech32(senderAddress)) + for shardID, balanceNonce := range FetchBalance(senderAddress) { + fmt.Printf(" Balance in Shard %d: %s, nonce: %v \n", shardID, convertBalanceIntoReadableFormat(balanceNonce.balance), balanceNonce.nonce) + } +} + +func convertBalanceIntoReadableFormat(balance *big.Int) string { + balance = balance.Div(balance, big.NewInt(denominations.Nano)) + strBalance := fmt.Sprintf("%d", balance.Uint64()) + + bytes := []byte(strBalance) + hasDecimal := false + for i := 0; i < 11; i++ { + if len(bytes)-1-i < 0 { + bytes = append([]byte{'0'}, bytes...) + } + if bytes[len(bytes)-1-i] != '0' && i < 9 { + hasDecimal = true + } + if i == 9 { + newBytes := append([]byte{'.'}, bytes[len(bytes)-i:]...) + bytes = append(bytes[:len(bytes)-i], newBytes...) + } + } + zerosToRemove := 0 + for i := 0; i < len(bytes); i++ { + if hasDecimal { + if bytes[len(bytes)-1-i] == '0' { + bytes = bytes[:len(bytes)-1-i] + i-- + } else { + break + } + } else { + if zerosToRemove < 5 { + bytes = bytes[:len(bytes)-1-i] + i-- + zerosToRemove++ + } else { + break + } + } + } + return string(bytes) +} + +// FetchBalance fetches account balance of specified address from the Harmony network +func FetchBalance(address common.Address) []*AccountState { + result := []*AccountState{} + for shardID := 0; shardID < walletProfile.Shards; shardID++ { + // Fill in nil pointers for each shard; nil represent failed balance fetch. + result = append(result, nil) + } + + var wg sync.WaitGroup + wg.Add(walletProfile.Shards) + + for shardID := 0; shardID < walletProfile.Shards; shardID++ { + go func(shardID int) { + defer wg.Done() + balance := big.NewInt(0) + var nonce uint64 + result[uint32(shardID)] = &AccountState{balance, 0} + + var wgShard sync.WaitGroup + wgShard.Add(len(walletProfile.RPCServer[shardID])) + + var mutexAccountState = &sync.Mutex{} + + for rpcServerID := 0; rpcServerID < len(walletProfile.RPCServer[shardID]); rpcServerID++ { + go func(rpcServerID int) { + for retry := 0; retry < rpcRetry; retry++ { + + server := walletProfile.RPCServer[shardID][rpcServerID] + client, err := clientService.NewClient(server.IP, server.Port) + if err != nil { + continue + } + + log.Debug("FetchBalance", "server", server) + response, err := client.GetBalance(address) + if err != nil { + log.Info("failed to get balance, retrying ...") + time.Sleep(200 * time.Millisecond) + continue + } + log.Debug("FetchBalance", "response", response) + respBalance := big.NewInt(0) + respBalance.SetBytes(response.Balance) + + mutexAccountState.Lock() + if balance.Cmp(respBalance) < 0 { + balance.SetBytes(response.Balance) + nonce = response.Nonce + } + mutexAccountState.Unlock() + break + } + wgShard.Done() + }(rpcServerID) + } + wgShard.Wait() + + result[shardID] = &AccountState{balance, nonce} + }(shardID) + } + wg.Wait() + return result +} + +// GetFreeToken requests for token test token on each shard +func GetFreeToken(address common.Address) { + for i := 0; i < walletProfile.Shards; i++ { + // use the 1st server (leader) to make the getFreeToken call + server := walletProfile.RPCServer[i][0] + client, err := clientService.NewClient(server.IP, server.Port) + if err != nil { + continue + } + + log.Debug("GetFreeToken", "server", server) + + for retry := 0; retry < rpcRetry; retry++ { + response, err := client.GetFreeToken(address) + if err != nil { + log.Info("failed to get free token, retrying ...") + time.Sleep(200 * time.Millisecond) + continue + } + log.Debug("GetFreeToken", "response", response) + txID := common.Hash{} + txID.SetBytes(response.TxId) + fmt.Printf("Transaction Id requesting free token in shard %d: %s\n", i, txID.Hex()) + break + } + } +} + +// clearKeystore deletes all data in the local keystore +func clearKeystore() { + dir, err := ioutil.ReadDir(keystoreDir) + if err != nil { + panic("Failed to read keystore directory") + } + for _, d := range dir { + subdir := path.Join([]string{keystoreDir, d.Name()}...) + if err := os.RemoveAll(subdir); err != nil { + fmt.Println(ctxerror.New("cannot remove directory", + "path", subdir).WithCause(err)) + } + } + fmt.Println("All existing accounts deleted...") +} + +// submitTransaction submits the transaction to the Harmony network +func submitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uint32) error { + msg := proto_node.ConstructTransactionListMessageAccount(types.Transactions{tx}) + clientGroup := p2p.NewClientGroupIDByShardID(p2p.ShardID(shardID)) + + err := walletNode.GetHost().SendMessageToGroups([]p2p.GroupID{clientGroup}, p2p_host.ConstructP2pMessage(byte(0), msg)) + if err != nil { + fmt.Printf("Error in SubmitTransaction: %v\n", err) + return err + } + fmt.Printf("Transaction Id for shard %d: %s\n", int(shardID), tx.Hash().Hex()) + // FIXME (leo): how to we know the tx was successful sent to the network + // this is a hacky way to wait for sometime + time.Sleep(3 * time.Second) + return nil +} diff --git a/internal/configs/sharding/fixedschedule.go b/internal/configs/sharding/fixedschedule.go index db7f4057f..5df96ae42 100644 --- a/internal/configs/sharding/fixedschedule.go +++ b/internal/configs/sharding/fixedschedule.go @@ -2,6 +2,7 @@ package shardingconfig import ( "math/big" + "time" "github.com/harmony-one/harmony/common/denominations" ) @@ -52,12 +53,17 @@ func (s fixedSchedule) MaxNumTxsPerBlockLimit() int { return mainnetMaxNumTxsPerBlockLimit } +func (s fixedSchedule) RecentTxDuration() time.Duration { + return mainnetRecentTxDuration +} + func (s fixedSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ MaxTxAmountLimit: s.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: s.MaxNumRecentTxsPerAccountLimit(), MaxTxPoolSizeLimit: s.MaxTxPoolSizeLimit(), MaxNumTxsPerBlockLimit: s.MaxNumTxsPerBlockLimit(), + RecentTxDuration: s.RecentTxDuration(), } } diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index 4416fa674..06d416e18 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -2,6 +2,7 @@ package shardingconfig import ( "math/big" + "time" "github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/internal/genesis" @@ -24,6 +25,7 @@ const ( localnetMaxNumRecentTxsPerAccountLimit = 2 localnetMaxTxPoolSizeLimit = 8000 localnetMaxNumTxsPerBlockLimit = 1000 + localnetRecentTxDuration = 100 * time.Second ) func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -81,12 +83,17 @@ func (ls localnetSchedule) MaxNumTxsPerBlockLimit() int { return localnetMaxNumTxsPerBlockLimit } +func (ls localnetSchedule) RecentTxDuration() time.Duration { + return localnetRecentTxDuration +} + func (ls localnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ MaxTxAmountLimit: ls.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: ls.MaxNumRecentTxsPerAccountLimit(), MaxTxPoolSizeLimit: ls.MaxTxPoolSizeLimit(), MaxNumTxsPerBlockLimit: ls.MaxNumTxsPerBlockLimit(), + RecentTxDuration: ls.RecentTxDuration(), } } diff --git a/internal/configs/sharding/mainnet.go b/internal/configs/sharding/mainnet.go index 5749a4914..865548575 100644 --- a/internal/configs/sharding/mainnet.go +++ b/internal/configs/sharding/mainnet.go @@ -2,6 +2,7 @@ package shardingconfig import ( "math/big" + "time" "github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/internal/genesis" @@ -15,9 +16,10 @@ const ( mainnetV3Epoch = 8 mainnetMaxTxAmountLimit = 1e3 // unit is in One - mainnetMaxNumRecentTxsPerAccountLimit = 10 + mainnetMaxNumRecentTxsPerAccountLimit = 1e2 mainnetMaxTxPoolSizeLimit = 8000 mainnetMaxNumTxsPerBlockLimit = 1000 + mainnetRecentTxDuration = time.Hour ) // MainnetSchedule is the mainnet sharding configuration schedule. @@ -85,12 +87,17 @@ func (ms mainnetSchedule) MaxNumTxsPerBlockLimit() int { return mainnetMaxNumTxsPerBlockLimit } +func (ms mainnetSchedule) RecentTxDuration() time.Duration { + return mainnetRecentTxDuration +} + func (ms mainnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ MaxTxAmountLimit: ms.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: ms.MaxNumRecentTxsPerAccountLimit(), MaxTxPoolSizeLimit: ms.MaxTxPoolSizeLimit(), MaxNumTxsPerBlockLimit: ms.MaxNumTxsPerBlockLimit(), + RecentTxDuration: ms.RecentTxDuration(), } } diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index 1b6feb2cf..8a2d6f820 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -4,6 +4,7 @@ package shardingconfig import ( "math/big" + "time" "github.com/harmony-one/harmony/internal/genesis" ) @@ -34,6 +35,9 @@ type Schedule interface { // Max total number of transactions allowed to be processed per block MaxNumTxsPerBlockLimit() int + // How long "recent" means for transaction in time Duration unit + RecentTxDuration() time.Duration + // configuration for throttling pending transactions TxsThrottleConfig() *TxsThrottleConfig } @@ -92,6 +96,9 @@ type TxsThrottleConfig struct { // Max amount limit for a valid transaction MaxTxAmountLimit *big.Int + // Max number of transactions of a particular account for the past hour + RecentTxDuration time.Duration + // Max number of transactions of a particular account for the past hour MaxNumRecentTxsPerAccountLimit uint64 diff --git a/internal/configs/sharding/testnet.go b/internal/configs/sharding/testnet.go index a472bb417..d3b740047 100644 --- a/internal/configs/sharding/testnet.go +++ b/internal/configs/sharding/testnet.go @@ -2,6 +2,7 @@ package shardingconfig import ( "math/big" + "time" "github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/internal/genesis" @@ -21,9 +22,10 @@ const ( threeOne = 111 testnetMaxTxAmountLimit = 1e3 // unit is in One - testnetMaxNumRecentTxsPerAccountLimit = 10 + testnetMaxNumRecentTxsPerAccountLimit = 1e2 testnetMaxTxPoolSizeLimit = 8000 testnetMaxNumTxsPerBlockLimit = 1000 + testnetRecentTxDuration = time.Hour ) func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -82,12 +84,17 @@ func (ts testnetSchedule) MaxNumTxsPerBlockLimit() int { return testnetMaxNumTxsPerBlockLimit } +func (ts testnetSchedule) RecentTxDuration() time.Duration { + return testnetRecentTxDuration +} + func (ts testnetSchedule) TxsThrottleConfig() *TxsThrottleConfig { return &TxsThrottleConfig{ MaxTxAmountLimit: ts.MaxTxAmountLimit(), MaxNumRecentTxsPerAccountLimit: ts.MaxNumRecentTxsPerAccountLimit(), MaxTxPoolSizeLimit: ts.MaxTxPoolSizeLimit(), MaxNumTxsPerBlockLimit: ts.MaxNumTxsPerBlockLimit(), + RecentTxDuration: ts.RecentTxDuration(), } } diff --git a/node/node.go b/node/node.go index 62d665b63..76e2d7d43 100644 --- a/node/node.go +++ b/node/node.go @@ -259,12 +259,14 @@ func (node *Node) AddPendingTransaction(newTx *types.Transaction) { func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Transactions { node.pendingTxMutex.Lock() + txsThrottleConfig := core.ShardingSchedule.TxsThrottleConfig() + // the next block number to be added in consensus protocol, which is always one more than current chain header block newBlockNum := node.Blockchain().CurrentBlock().NumberU64() + 1 - // remove old (currently > 1 hr) blockNum keys from recentTxsStats and initiailize for the new block + // remove old (> txsThrottleConfigRecentTxDuration) blockNum keys from recentTxsStats and initiailize for the new block for blockNum := range node.recentTxsStats { - blockNumHourAgo := uint64(time.Hour / node.BlockPeriod) + blockNumHourAgo := uint64(txsThrottleConfig.RecentTxDuration / node.BlockPeriod) if blockNumHourAgo < newBlockNum-blockNum { delete(node.recentTxsStats, blockNum) @@ -272,7 +274,7 @@ func (node *Node) getTransactionsForNewBlock(coinbase common.Address) types.Tran } node.recentTxsStats[newBlockNum] = make(types.BlockTxsCounts) - selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(newBlockNum, node.pendingTransactions, node.recentTxsStats, core.ShardingSchedule.TxsThrottleConfig(), coinbase) + selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(newBlockNum, node.pendingTransactions, node.recentTxsStats, txsThrottleConfig, coinbase) node.pendingTransactions = unselected node.reducePendingTransactions() diff --git a/node/worker/worker.go b/node/worker/worker.go index 78468993f..32d9f977e 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -109,6 +109,7 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra for _, tx := range txs { if tx.ShardID() != w.shardID { invalid = append(invalid, tx) + continue } sender, flag := w.throttleTxs(selected, recentTxsStats, txsThrottleConfig, tx) diff --git a/scripts/go_executable_build.sh b/scripts/go_executable_build.sh index 0ea616a16..1a7cdf6df 100755 --- a/scripts/go_executable_build.sh +++ b/scripts/go_executable_build.sh @@ -7,6 +7,7 @@ SRC[harmony]=cmd/harmony/main.go SRC[txgen]=cmd/client/txgen/main.go SRC[bootnode]=cmd/bootnode/main.go SRC[wallet]="cmd/client/wallet/main.go cmd/client/wallet/generated_wallet.ini.go" +SRC[wallet_stress_test]="cmd/client/wallet_stress_test/main.go cmd/client/wallet_stress_test/generated_wallet.ini.go" BINDIR=bin BUCKET=unique-bucket-bin From fa9648a7abbb03a55e9bfabfa2a1f3c24499e2d5 Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Mon, 12 Aug 2019 23:19:10 -0700 Subject: [PATCH 18/20] update generated_wallet.ini.go to date --- cmd/client/wallet/generated_wallet.ini.go | 68 ++++--------------- .../generated_wallet.ini.go | 12 ---- 2 files changed, 15 insertions(+), 65 deletions(-) diff --git a/cmd/client/wallet/generated_wallet.ini.go b/cmd/client/wallet/generated_wallet.ini.go index 69c9ddf10..7784d36d8 100644 --- a/cmd/client/wallet/generated_wallet.ini.go +++ b/cmd/client/wallet/generated_wallet.ini.go @@ -4,83 +4,45 @@ const ( defaultWalletIni = `[default] bootnode = /ip4/100.26.90.187/tcp/9874/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv bootnode = /ip4/54.213.43.194/tcp/9874/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 -bootnode = /ip4/13.113.101.219/tcp/12019/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX -bootnode = /ip4/99.81.170.167/tcp/12019/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj shards = 4 - [default.shard0.rpc] rpc = l0.t.hmny.io:14555 rpc = s0.t.hmny.io:14555 - [default.shard1.rpc] rpc = l1.t.hmny.io:14555 rpc = s1.t.hmny.io:14555 - [default.shard2.rpc] rpc = l2.t.hmny.io:14555 rpc = s2.t.hmny.io:14555 - [default.shard3.rpc] rpc = l3.t.hmny.io:14555 rpc = s3.t.hmny.io:14555 - [local] bootnode = /ip4/127.0.0.1/tcp/19876/p2p/Qmc1V6W7BwX8Ugb42Ti8RnXF1rY5PF7nnZ6bKBryCgi6cv shards = 2 - [local.shard0.rpc] rpc = 127.0.0.1:14555 rpc = 127.0.0.1:14557 rpc = 127.0.0.1:14559 - [local.shard1.rpc] rpc = 127.0.0.1:14556 rpc = 127.0.0.1:14558 rpc = 127.0.0.1:14560 - -[beta] -bootnode = /ip4/54.213.43.194/tcp/9868/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 -bootnode = /ip4/100.26.90.187/tcp/9868/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv -bootnode = /ip4/13.113.101.219/tcp/12018/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX -shards = 4 - -[beta.shard0.rpc] -rpc = l0.b.hmny.io:14555 -rpc = s0.b.hmny.io:14555 - -[beta.shard1.rpc] -rpc = l1.b.hmny.io:14555 -rpc = s1.b.hmny.io:14555 - -[beta.shard2.rpc] -rpc = l2.b.hmny.io:14555 -rpc = s2.b.hmny.io:14555 - -[beta.shard3.rpc] -rpc = l3.b.hmny.io:14555 -rpc = s3.b.hmny.io:14555 - -[pangaea] -bootnode = /ip4/100.26.90.187/tcp/9867/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv -bootnode = /ip4/54.213.43.194/tcp/9867/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 -bootnode = /ip4/13.113.101.219/tcp/9867/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX -bootnode = /ip4/99.81.170.167/tcp/9867/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj +[devnet] +bootnode = /ip4/100.26.90.187/tcp/9871/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv +bootnode = /ip4/54.213.43.194/tcp/9871/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj shards = 4 - -[pangaea.shard0.rpc] -rpc = l0.p.hmny.io:14555 -rpc = s0.p.hmny.io:14555 - -[pangaea.shard1.rpc] -rpc = l1.p.hmny.io:14555 -rpc = s1.p.hmny.io:14555 - -[pangaea.shard2.rpc] -rpc = l2.p.hmny.io:14555 -rpc = s2.p.hmny.io:14555 - -[pangaea.shard3.rpc] -rpc = l3.p.hmny.io:14555 -rpc = s3.p.hmny.io:14555 +[devnet.shard0.rpc] +rpc = l0.t1.hmny.io:14555 +rpc = s0.t1.hmny.io:14555 +[devnet.shard1.rpc] +rpc = l1.t1.hmny.io:14555 +rpc = s1.t1.hmny.io:14555 +[devnet.shard2.rpc] +rpc = l2.t1.hmny.io:14555 +rpc = s2.t1.hmny.io:14555 +[devnet.shard3.rpc] +rpc = l3.t1.hmny.io:14555 +rpc = s3.t1.hmny.io:14555 ` ) diff --git a/cmd/client/wallet_stress_test/generated_wallet.ini.go b/cmd/client/wallet_stress_test/generated_wallet.ini.go index b1ed56eff..7784d36d8 100644 --- a/cmd/client/wallet_stress_test/generated_wallet.ini.go +++ b/cmd/client/wallet_stress_test/generated_wallet.ini.go @@ -5,54 +5,42 @@ const ( bootnode = /ip4/100.26.90.187/tcp/9874/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv bootnode = /ip4/54.213.43.194/tcp/9874/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 shards = 4 - [default.shard0.rpc] rpc = l0.t.hmny.io:14555 rpc = s0.t.hmny.io:14555 - [default.shard1.rpc] rpc = l1.t.hmny.io:14555 rpc = s1.t.hmny.io:14555 - [default.shard2.rpc] rpc = l2.t.hmny.io:14555 rpc = s2.t.hmny.io:14555 - [default.shard3.rpc] rpc = l3.t.hmny.io:14555 rpc = s3.t.hmny.io:14555 - [local] bootnode = /ip4/127.0.0.1/tcp/19876/p2p/Qmc1V6W7BwX8Ugb42Ti8RnXF1rY5PF7nnZ6bKBryCgi6cv shards = 2 - [local.shard0.rpc] rpc = 127.0.0.1:14555 rpc = 127.0.0.1:14557 rpc = 127.0.0.1:14559 - [local.shard1.rpc] rpc = 127.0.0.1:14556 rpc = 127.0.0.1:14558 rpc = 127.0.0.1:14560 - [devnet] bootnode = /ip4/100.26.90.187/tcp/9871/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv bootnode = /ip4/54.213.43.194/tcp/9871/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj shards = 4 - [devnet.shard0.rpc] rpc = l0.t1.hmny.io:14555 rpc = s0.t1.hmny.io:14555 - [devnet.shard1.rpc] rpc = l1.t1.hmny.io:14555 rpc = s1.t1.hmny.io:14555 - [devnet.shard2.rpc] rpc = l2.t1.hmny.io:14555 rpc = s2.t1.hmny.io:14555 - [devnet.shard3.rpc] rpc = l3.t1.hmny.io:14555 rpc = s3.t1.hmny.io:14555 From 8e926cce030202800a6eedae399ef246f2a5a27c Mon Sep 17 00:00:00 2001 From: Dennis Won Date: Tue, 13 Aug 2019 21:46:48 -0700 Subject: [PATCH 19/20] stress test script updates --- cmd/client/wallet_stress_test/main.go | 77 +++++++++++++++++---------- internal/configs/sharding/localnet.go | 2 +- node/worker/worker.go | 11 +--- 3 files changed, 52 insertions(+), 38 deletions(-) diff --git a/cmd/client/wallet_stress_test/main.go b/cmd/client/wallet_stress_test/main.go index a03aa73de..df6bdb9bd 100644 --- a/cmd/client/wallet_stress_test/main.go +++ b/cmd/client/wallet_stress_test/main.go @@ -33,10 +33,11 @@ import ( ) var ( - version string - builtBy string - builtAt string - commit string + version string + builtBy string + builtAt string + commit string + nextNonce uint64 ) func printVersion(me string) { @@ -213,18 +214,14 @@ func processStressTestCommand() { */ + fmt.Println("Creating wallet node") + walletNode := createWalletNode() + senderAddress := common2.ParseAddr("one1uyshu2jgv8w465yc8kkny36thlt2wvel89tcmg") receiverAddress := common2.ParseAddr("one1spshr72utf6rwxseaz339j09ed8p6f8ke370zj") shardID := 1 - walletNode := createWalletNode() - - shardIDToAccountState := FetchBalance(senderAddress) - state := shardIDToAccountState[shardID] - - balance := state.balance - // amount 1/10th of the balance - amountBigInt := balance.Div(balance, big.NewInt(10)) + fmt.Printf("Sender account: %s:\n", common2.MustAddressToBech32(senderAddress)) // default inputData data := make([]byte, 0) @@ -235,12 +232,49 @@ func processStressTestCommand() { gasPriceBigInt := big.NewInt(int64(gasPrice)) gasPriceBigInt = gasPriceBigInt.Mul(gasPriceBigInt, big.NewInt(denominations.Nano)) + fmt.Printf("gas limit: %d, gas price: %d", gasLimit, gasPriceBigInt.Uint64()) + senderPass := "" - for i := 0; i < 4; i++ { - currNonce := state.nonce + var shardIDToAccountStateSender []*AccountState + var shardIDToAccountStateReceiver []*AccountState + var senderState *AccountState + var receiverState *AccountState + var retry uint32 + + for i := 0; i < 10; i++ { + for retry = 0; retry < 10; retry++ { + shardIDToAccountStateSender = FetchBalance(senderAddress) + shardIDToAccountStateReceiver = FetchBalance(receiverAddress) + + senderState = shardIDToAccountStateSender[shardID] + receiverState = shardIDToAccountStateReceiver[shardID] + + if senderState.nonce == nextNonce { + break + } + time.Sleep(3 * time.Second) + fmt.Printf(".") + } + + if retry == 10 { + fmt.Printf("\nRetry expired. Num txs made: %d\n", i) + break + } + + nextNonce++ + + senderBalance := senderState.balance + receiverBalance := receiverState.balance + + // amount 1/10th of the balance + amountBigInt := senderBalance.Div(senderBalance, big.NewInt(10)) + + fmt.Printf("\nsender: balance (shard %d: %s, nonce: %v)\n", shardID, convertBalanceIntoReadableFormat(senderBalance), senderState.nonce) + fmt.Printf("receiver balance (shard %d: %s, nonce: %v)\n", shardID, convertBalanceIntoReadableFormat(receiverBalance), receiverState.nonce) + tx := types.NewTransaction( - currNonce, receiverAddress, uint32(shardID), amountBigInt, + senderState.nonce, receiverAddress, uint32(shardID), amountBigInt, gasLimit, gasPriceBigInt, data) account, _ := ks.Find(accounts.Account{Address: senderAddress}) @@ -253,21 +287,10 @@ func processStressTestCommand() { fmt.Println(ctxerror.New("submitTransaction failed", "tx", tx, "shardID", shardID).WithCause(err)) } - - for retry := 0; retry < 10; retry++ { - accountStates := FetchBalance(senderAddress) - state = accountStates[shardID] - fmt.Println("state.nonce", state.nonce) - if state.nonce == currNonce+1 { - break - } - time.Sleep(3 * time.Second) - } } - fmt.Printf("Sender Account: %s:\n", common2.MustAddressToBech32(senderAddress)) for shardID, balanceNonce := range FetchBalance(senderAddress) { - fmt.Printf(" Balance in Shard %d: %s, nonce: %v \n", shardID, convertBalanceIntoReadableFormat(balanceNonce.balance), balanceNonce.nonce) + fmt.Printf(" Final: Balance in Shard %d: %s, nonce: %v \n", shardID, convertBalanceIntoReadableFormat(balanceNonce.balance), balanceNonce.nonce) } } diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index 06d416e18..bd74d591e 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -25,7 +25,7 @@ const ( localnetMaxNumRecentTxsPerAccountLimit = 2 localnetMaxTxPoolSizeLimit = 8000 localnetMaxNumTxsPerBlockLimit = 1000 - localnetRecentTxDuration = 100 * time.Second + localnetRecentTxDuration = 10 * time.Second ) func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { diff --git a/node/worker/worker.go b/node/worker/worker.go index 32d9f977e..c56b99a33 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -47,17 +47,8 @@ type Worker struct { // the second is the throttling result enum for the transaction of interest. // Throttling happens based on the amount, frequency, etc. func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.RecentTxsStats, txsThrottleConfig *shardingconfig.TxsThrottleConfig, tx *types.Transaction) (common.Address, shardingconfig.TxThrottleFlag) { - chainID := tx.ChainID() - // Depending on the presence of the chain ID, sign with EIP155 or homestead - var s types.Signer - if chainID != nil { - s = types.NewEIP155Signer(chainID) - } else { - s = types.HomesteadSigner{} - } - var sender common.Address - msg, err := tx.AsMessage(s) + msg, err := tx.AsMessage(types.MakeSigner(w.config, w.chain.CurrentBlock().Number())) if err != nil { utils.GetLogInstance().Error("Error when parsing tx into message", "tx Id", tx.Hash().Hex(), "err", err) From 639406ba635cf4e0db6c0af59a483bcf143a81b1 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Wed, 14 Aug 2019 10:44:18 -0700 Subject: [PATCH 20/20] [wallet] update generated wallet.ini Signed-off-by: Leo Chen --- cmd/client/wallet/generated_wallet.ini.go | 68 +++++++++++++++---- .../generated_wallet.ini.go | 68 +++++++++++++++---- 2 files changed, 106 insertions(+), 30 deletions(-) diff --git a/cmd/client/wallet/generated_wallet.ini.go b/cmd/client/wallet/generated_wallet.ini.go index 7784d36d8..69c9ddf10 100644 --- a/cmd/client/wallet/generated_wallet.ini.go +++ b/cmd/client/wallet/generated_wallet.ini.go @@ -4,45 +4,83 @@ const ( defaultWalletIni = `[default] bootnode = /ip4/100.26.90.187/tcp/9874/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv bootnode = /ip4/54.213.43.194/tcp/9874/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 +bootnode = /ip4/13.113.101.219/tcp/12019/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX +bootnode = /ip4/99.81.170.167/tcp/12019/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj shards = 4 + [default.shard0.rpc] rpc = l0.t.hmny.io:14555 rpc = s0.t.hmny.io:14555 + [default.shard1.rpc] rpc = l1.t.hmny.io:14555 rpc = s1.t.hmny.io:14555 + [default.shard2.rpc] rpc = l2.t.hmny.io:14555 rpc = s2.t.hmny.io:14555 + [default.shard3.rpc] rpc = l3.t.hmny.io:14555 rpc = s3.t.hmny.io:14555 + [local] bootnode = /ip4/127.0.0.1/tcp/19876/p2p/Qmc1V6W7BwX8Ugb42Ti8RnXF1rY5PF7nnZ6bKBryCgi6cv shards = 2 + [local.shard0.rpc] rpc = 127.0.0.1:14555 rpc = 127.0.0.1:14557 rpc = 127.0.0.1:14559 + [local.shard1.rpc] rpc = 127.0.0.1:14556 rpc = 127.0.0.1:14558 rpc = 127.0.0.1:14560 -[devnet] -bootnode = /ip4/100.26.90.187/tcp/9871/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv -bootnode = /ip4/54.213.43.194/tcp/9871/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj + +[beta] +bootnode = /ip4/54.213.43.194/tcp/9868/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 +bootnode = /ip4/100.26.90.187/tcp/9868/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv +bootnode = /ip4/13.113.101.219/tcp/12018/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX +shards = 4 + +[beta.shard0.rpc] +rpc = l0.b.hmny.io:14555 +rpc = s0.b.hmny.io:14555 + +[beta.shard1.rpc] +rpc = l1.b.hmny.io:14555 +rpc = s1.b.hmny.io:14555 + +[beta.shard2.rpc] +rpc = l2.b.hmny.io:14555 +rpc = s2.b.hmny.io:14555 + +[beta.shard3.rpc] +rpc = l3.b.hmny.io:14555 +rpc = s3.b.hmny.io:14555 + +[pangaea] +bootnode = /ip4/100.26.90.187/tcp/9867/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv +bootnode = /ip4/54.213.43.194/tcp/9867/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 +bootnode = /ip4/13.113.101.219/tcp/9867/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX +bootnode = /ip4/99.81.170.167/tcp/9867/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj shards = 4 -[devnet.shard0.rpc] -rpc = l0.t1.hmny.io:14555 -rpc = s0.t1.hmny.io:14555 -[devnet.shard1.rpc] -rpc = l1.t1.hmny.io:14555 -rpc = s1.t1.hmny.io:14555 -[devnet.shard2.rpc] -rpc = l2.t1.hmny.io:14555 -rpc = s2.t1.hmny.io:14555 -[devnet.shard3.rpc] -rpc = l3.t1.hmny.io:14555 -rpc = s3.t1.hmny.io:14555 + +[pangaea.shard0.rpc] +rpc = l0.p.hmny.io:14555 +rpc = s0.p.hmny.io:14555 + +[pangaea.shard1.rpc] +rpc = l1.p.hmny.io:14555 +rpc = s1.p.hmny.io:14555 + +[pangaea.shard2.rpc] +rpc = l2.p.hmny.io:14555 +rpc = s2.p.hmny.io:14555 + +[pangaea.shard3.rpc] +rpc = l3.p.hmny.io:14555 +rpc = s3.p.hmny.io:14555 ` ) diff --git a/cmd/client/wallet_stress_test/generated_wallet.ini.go b/cmd/client/wallet_stress_test/generated_wallet.ini.go index 7784d36d8..69c9ddf10 100644 --- a/cmd/client/wallet_stress_test/generated_wallet.ini.go +++ b/cmd/client/wallet_stress_test/generated_wallet.ini.go @@ -4,45 +4,83 @@ const ( defaultWalletIni = `[default] bootnode = /ip4/100.26.90.187/tcp/9874/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv bootnode = /ip4/54.213.43.194/tcp/9874/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 +bootnode = /ip4/13.113.101.219/tcp/12019/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX +bootnode = /ip4/99.81.170.167/tcp/12019/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj shards = 4 + [default.shard0.rpc] rpc = l0.t.hmny.io:14555 rpc = s0.t.hmny.io:14555 + [default.shard1.rpc] rpc = l1.t.hmny.io:14555 rpc = s1.t.hmny.io:14555 + [default.shard2.rpc] rpc = l2.t.hmny.io:14555 rpc = s2.t.hmny.io:14555 + [default.shard3.rpc] rpc = l3.t.hmny.io:14555 rpc = s3.t.hmny.io:14555 + [local] bootnode = /ip4/127.0.0.1/tcp/19876/p2p/Qmc1V6W7BwX8Ugb42Ti8RnXF1rY5PF7nnZ6bKBryCgi6cv shards = 2 + [local.shard0.rpc] rpc = 127.0.0.1:14555 rpc = 127.0.0.1:14557 rpc = 127.0.0.1:14559 + [local.shard1.rpc] rpc = 127.0.0.1:14556 rpc = 127.0.0.1:14558 rpc = 127.0.0.1:14560 -[devnet] -bootnode = /ip4/100.26.90.187/tcp/9871/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv -bootnode = /ip4/54.213.43.194/tcp/9871/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj + +[beta] +bootnode = /ip4/54.213.43.194/tcp/9868/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 +bootnode = /ip4/100.26.90.187/tcp/9868/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv +bootnode = /ip4/13.113.101.219/tcp/12018/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX +shards = 4 + +[beta.shard0.rpc] +rpc = l0.b.hmny.io:14555 +rpc = s0.b.hmny.io:14555 + +[beta.shard1.rpc] +rpc = l1.b.hmny.io:14555 +rpc = s1.b.hmny.io:14555 + +[beta.shard2.rpc] +rpc = l2.b.hmny.io:14555 +rpc = s2.b.hmny.io:14555 + +[beta.shard3.rpc] +rpc = l3.b.hmny.io:14555 +rpc = s3.b.hmny.io:14555 + +[pangaea] +bootnode = /ip4/100.26.90.187/tcp/9867/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv +bootnode = /ip4/54.213.43.194/tcp/9867/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 +bootnode = /ip4/13.113.101.219/tcp/9867/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX +bootnode = /ip4/99.81.170.167/tcp/9867/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj shards = 4 -[devnet.shard0.rpc] -rpc = l0.t1.hmny.io:14555 -rpc = s0.t1.hmny.io:14555 -[devnet.shard1.rpc] -rpc = l1.t1.hmny.io:14555 -rpc = s1.t1.hmny.io:14555 -[devnet.shard2.rpc] -rpc = l2.t1.hmny.io:14555 -rpc = s2.t1.hmny.io:14555 -[devnet.shard3.rpc] -rpc = l3.t1.hmny.io:14555 -rpc = s3.t1.hmny.io:14555 + +[pangaea.shard0.rpc] +rpc = l0.p.hmny.io:14555 +rpc = s0.p.hmny.io:14555 + +[pangaea.shard1.rpc] +rpc = l1.p.hmny.io:14555 +rpc = s1.p.hmny.io:14555 + +[pangaea.shard2.rpc] +rpc = l2.p.hmny.io:14555 +rpc = s2.p.hmny.io:14555 + +[pangaea.shard3.rpc] +rpc = l3.p.hmny.io:14555 +rpc = s3.p.hmny.io:14555 ` )