package simulated import ( "context" "crypto/ecdsa" "math/big" "testing" "time" "github.com/XinFinOrg/XDPoSChain/core/types" ) // TestTransactionRollbackBehavior tests that calling Rollback on the simulated backend doesn't prevent subsequent // addition of new transactions func TestTransactionRollbackBehavior(t *testing.T) { sim := New( types.GenesisAlloc{ testAddr: {Balance: big.NewInt(10000000000000000)}, testAddr2: {Balance: big.NewInt(10000000000000000)}, }, 10000000, ) defer sim.Close() client := sim.Client() btx0 := testSendSignedTx(t, testKey, sim) tx0 := testSendSignedTx(t, testKey2, sim) tx1 := testSendSignedTx(t, testKey2, sim) sim.Rollback() if pendingStateHasTx(client, btx0) || pendingStateHasTx(client, tx0) || pendingStateHasTx(client, tx1) { t.Fatalf("all transactions were not rolled back") } btx2 := testSendSignedTx(t, testKey, sim) tx2 := testSendSignedTx(t, testKey2, sim) tx3 := testSendSignedTx(t, testKey2, sim) sim.Commit() if !pendingStateHasTx(client, btx2) || !pendingStateHasTx(client, tx2) || !pendingStateHasTx(client, tx3) { t.Fatalf("all post-rollback transactions were not included") } } // testSendSignedTx sends a signed transaction to the simulated backend. // It does not commit the block. func testSendSignedTx(t *testing.T, key *ecdsa.PrivateKey, sim *Backend) *types.Transaction { t.Helper() client := sim.Client() ctx := context.Background() var ( err error signedTx *types.Transaction ) signedTx, err = newTx(sim, key) if err != nil { t.Fatalf("failed to create transaction: %v", err) } if err = client.SendTransaction(ctx, signedTx); err != nil { t.Fatalf("failed to send transaction: %v", err) } return signedTx } // pendingStateHasTx returns true if a given transaction was successfully included as of the latest pending state. func pendingStateHasTx(client Client, tx *types.Transaction) bool { ctx := context.Background() var ( receipt *types.Receipt err error ) // Poll for receipt with timeout deadline := time.Now().Add(2 * time.Second) for time.Now().Before(deadline) { receipt, err = client.TransactionReceipt(ctx, tx.Hash()) if err == nil && receipt != nil { break } time.Sleep(100 * time.Millisecond) } if err != nil { return false } if receipt == nil { return false } if receipt.Status != types.ReceiptStatusSuccessful { return false } return true }