Skip to content

Commit

Permalink
Remove waiting for the next block in e2e tests (#485)
Browse files Browse the repository at this point in the history
* Remove the waitForBlock method in TestTxPool_TransactionCoalescing

* Add configurable block time for the test server

* Remove waitForBlock in TestPoS_UnstakeExploit

* Remove waitForBlock in TestPoS_StakeUnstakeExploit

* Extract commong gas total wait logic, remove waitForBlock in TestPoS_StakeUnstakeWithinSameBlock

* Remove waitForBlock

* Make the gas usage wait func concurrent

* Rename method to be more clear

* Add context to TestPoS_UnstakeExploit

* Add context to TestTxPool_TransactionCoalescing

* Add timeout to TestTxPool_TransactionCoalescing

* Add comment to TestTxPool_TransactionCoalescing

* Add t.Helper() in GetGasTotal

* Increase block gas limit for TestPoS_UnstakeExploit
  • Loading branch information
zivkovicmilos authored May 4, 2022
1 parent f91feef commit b74ffa8
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 72 deletions.
5 changes: 5 additions & 0 deletions e2e/framework/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type TestServerConfig struct {
Signer *crypto.EIP155Signer // Signer used for transactions
MinValidatorCount uint64 // Min validator count
MaxValidatorCount uint64 // Max validator count
BlockTime uint64 // Minimum block generation time (in s)
}

// DataDir returns path of data directory server uses
Expand All @@ -64,6 +65,10 @@ func (t *TestServerConfig) SetSigner(signer *crypto.EIP155Signer) {
t.Signer = signer
}

func (t *TestServerConfig) SetBlockTime(blockTime uint64) {
t.BlockTime = blockTime
}

// PrivateKey returns a private key in data directory
func (t *TestServerConfig) PrivateKey() (*ecdsa.PrivateKey, error) {
return crypto.GenerateOrReadPrivateKey(filepath.Join(t.DataDir(), "consensus", ibft.IbftKeyName))
Expand Down
54 changes: 54 additions & 0 deletions e2e/framework/testserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"sync/atomic"
"testing"
"time"

Expand Down Expand Up @@ -355,6 +357,10 @@ func (t *TestServer) Start(ctx context.Context) error {
args = append(args, "--block-gas-target", *types.EncodeUint64(t.Config.BlockGasTarget))
}

if t.Config.BlockTime != 0 {
args = append(args, "--block-time", strconv.FormatUint(t.Config.BlockTime, 10))
}

t.ReleaseReservedPorts()

// Start the server
Expand Down Expand Up @@ -538,6 +544,54 @@ func (t *TestServer) WaitForReceipt(ctx context.Context, hash web3.Hash) (*web3.
return data.receipt, data.err
}

// GetGasTotal waits for the total gas used sum for the passed in
// transactions
func (t *TestServer) GetGasTotal(txHashes []web3.Hash) uint64 {
t.t.Helper()

var (
totalGasUsed = uint64(0)
receiptErrs = make([]error, 0)
receiptErrsLock sync.Mutex
wg sync.WaitGroup
)

appendReceiptErr := func(receiptErr error) {
receiptErrsLock.Lock()
defer receiptErrsLock.Unlock()

receiptErrs = append(receiptErrs, receiptErr)
}

for _, txHash := range txHashes {
wg.Add(1)

go func(txHash web3.Hash) {
defer wg.Done()

ctx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
defer cancelFn()

receipt, receiptErr := tests.WaitForReceipt(ctx, t.JSONRPC().Eth(), txHash)
if receiptErr != nil {
appendReceiptErr(fmt.Errorf("unable to wait for receipt, %w", receiptErr))

return
}

atomic.AddUint64(&totalGasUsed, receipt.GasUsed)
}(txHash)
}

wg.Wait()

if len(receiptErrs) > 0 {
t.t.Fatalf("unable to wait for receipts, %v", receiptErrs)
}

return totalGasUsed
}

func (t *TestServer) WaitForReady(ctx context.Context) error {
_, err := tests.RetryUntilTimeout(ctx, func() (interface{}, bool) {
num, err := t.GetLatestBlockHeight()
Expand Down
51 changes: 26 additions & 25 deletions e2e/pos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ func TestPoS_UnstakeExploit(t *testing.T) {
config.Premine(senderAddr, defaultBalance)
config.SetDevStakingAddresses(append(generateStakingAddresses(numDummyValidators), senderAddr))
config.SetIBFTPoS(true)
config.SetBlockLimit(5000000000)
})
srv := srvs[0]
client := srv.JSONRPC()
Expand Down Expand Up @@ -375,6 +376,8 @@ func TestPoS_UnstakeExploit(t *testing.T) {
return signedTx
}

txHashes := make([]web3.Hash, 0)

for i := 0; i < numTransactions; i++ {
var msg *txpoolOp.AddTxnReq

Expand All @@ -387,22 +390,23 @@ func TestPoS_UnstakeExploit(t *testing.T) {
From: types.ZeroAddress.String(),
}

_, addErr := clt.AddTxn(context.Background(), msg)
addCtx, addCtxCn := context.WithTimeout(context.Background(), time.Second*10)

addResp, addErr := clt.AddTxn(addCtx, msg)
if addErr != nil {
t.Fatalf("Unable to add txn, %v", addErr)
}
}

// Set up the blockchain listener to catch the added block event
blockNum := waitForBlock(t, srv, 1, 0)
txHashes = append(txHashes, web3.HexToHash(addResp.TxHash))

block, blockErr := client.Eth().GetBlockByNumber(web3.BlockNumber(blockNum), true)
if blockErr != nil {
t.Fatalf("Unable to fetch block")
addCtxCn()
}

// Wait for the transactions to go through
totalGasUsed := srv.GetGasTotal(txHashes)

// Find how much the address paid for all the transactions in this block
paidFee := big.NewInt(0).Mul(bigGasPrice, big.NewInt(int64(block.GasUsed)))
paidFee := big.NewInt(0).Mul(bigGasPrice, big.NewInt(int64(totalGasUsed)))

// Check the balances
actualAccountBalance := framework.GetAccountBalance(t, senderAddr, client)
Expand Down Expand Up @@ -517,6 +521,7 @@ func TestPoS_StakeUnstakeExploit(t *testing.T) {

oneEth := framework.EthToWei(1)
zeroEth := framework.EthToWei(0)
txHashes := make([]web3.Hash, 0)

for i := 0; i < numTransactions; i++ {
var msg *txpoolOp.AddTxnReq
Expand All @@ -539,22 +544,19 @@ func TestPoS_StakeUnstakeExploit(t *testing.T) {
}
}

_, addErr := txpoolClient.AddTxn(context.Background(), msg)
addResp, addErr := txpoolClient.AddTxn(context.Background(), msg)
if addErr != nil {
t.Fatalf("Unable to add txn, %v", addErr)
}

txHashes = append(txHashes, web3.HexToHash(addResp.TxHash))
}

// Set up the blockchain listener to catch the added block event
blockNum := waitForBlock(t, srv, 1, 0)

block, blockErr := client.Eth().GetBlockByNumber(web3.BlockNumber(blockNum), true)
if blockErr != nil {
t.Fatalf("Unable to fetch block")
}
totalGasUsed := srv.GetGasTotal(txHashes)

// Find how much the address paid for all the transactions in this block
paidFee := big.NewInt(0).Mul(bigGasPrice, big.NewInt(int64(block.GasUsed)))
paidFee := big.NewInt(0).Mul(bigGasPrice, big.NewInt(int64(totalGasUsed)))

// Check the balances
actualAccountBalance := framework.GetAccountBalance(t, senderAddr, client)
Expand Down Expand Up @@ -650,6 +652,8 @@ func TestPoS_StakeUnstakeWithinSameBlock(t *testing.T) {
}

zeroEth := framework.EthToWei(0)
txHashes := make([]web3.Hash, 0)

// addTxn is a helper method for generating and adding a transaction
// through the operator command
addTxn := func(value *big.Int, methodName string) {
Expand All @@ -661,10 +665,12 @@ func TestPoS_StakeUnstakeWithinSameBlock(t *testing.T) {
From: types.ZeroAddress.String(),
}

_, addErr := txpoolClient.AddTxn(context.Background(), txnMsg)
addResp, addErr := txpoolClient.AddTxn(context.Background(), txnMsg)
if addErr != nil {
t.Fatalf("Unable to add txn, %v", addErr)
}

txHashes = append(txHashes, web3.HexToHash(addResp.TxHash))
}

// Stake transaction
Expand All @@ -673,16 +679,11 @@ func TestPoS_StakeUnstakeWithinSameBlock(t *testing.T) {
// Unstake transaction
addTxn(zeroEth, "unstake")

// Set up the blockchain listener to catch the added block event
blockNum := waitForBlock(t, srv, 1, 0)

block, blockErr := client.Eth().GetBlockByNumber(web3.BlockNumber(blockNum), true)
if blockErr != nil {
t.Fatalf("Unable to fetch block")
}
// Wait for the transactions to go through
totalGasUsed := srv.GetGasTotal(txHashes)

// Find how much the address paid for all the transactions in this block
paidFee := big.NewInt(0).Mul(bigGasPrice, big.NewInt(int64(block.GasUsed)))
paidFee := big.NewInt(0).Mul(bigGasPrice, big.NewInt(int64(totalGasUsed)))

// Check the balances
actualAccountBalance := framework.GetAccountBalance(t, senderAddr, client)
Expand Down
Loading

0 comments on commit b74ffa8

Please sign in to comment.