فهرست منبع

core: transaction nonce recovery fix

When the transaction state recovery kicked in it assigned the last
(incorrect) nonce to the pending state which caused transactions with
the same nonce to occur.

Added test for nonce recovery
Jeffrey Wilcke 10 سال پیش
والد
کامیت
b60a27627b
2فایلهای تغییر یافته به همراه21 افزوده شده و 2 حذف شده
  1. 2 2
      core/transaction_pool.go
  2. 19 0
      core/transaction_pool_test.go

+ 2 - 2
core/transaction_pool.go

@@ -121,8 +121,8 @@ func (pool *TxPool) resetState() {
 		if addr, err := tx.From(); err == nil {
 			// Set the nonce. Transaction nonce can never be lower
 			// than the state nonce; validatePool took care of that.
-			if pool.pendingState.GetNonce(addr) < tx.Nonce() {
-				pool.pendingState.SetNonce(addr, tx.Nonce())
+			if pool.pendingState.GetNonce(addr) <= tx.Nonce() {
+				pool.pendingState.SetNonce(addr, tx.Nonce()+1)
 			}
 		}
 	}

+ 19 - 0
core/transaction_pool_test.go

@@ -219,3 +219,22 @@ func TestMissingNonce(t *testing.T) {
 		t.Error("expected 1 queued transaction, got", len(pool.queue[addr]))
 	}
 }
+
+func TestNonceRecovery(t *testing.T) {
+	const n = 10
+	pool, key := setupTxPool()
+	addr := crypto.PubkeyToAddress(key.PublicKey)
+	pool.currentState().SetNonce(addr, n)
+	pool.currentState().AddBalance(addr, big.NewInt(100000000000000))
+	pool.resetState()
+	tx := transaction(n, big.NewInt(100000), key)
+	if err := pool.Add(tx); err != nil {
+		t.Error(err)
+	}
+	// simulate some weird re-order of transactions and missing nonce(s)
+	pool.currentState().SetNonce(addr, n-1)
+	pool.resetState()
+	if fn := pool.pendingState.GetNonce(addr); fn != n+1 {
+		t.Errorf("expected nonce to be %d, got %d", n+1, fn)
+	}
+}