Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't use immature outputs when funding a transaction #24

Merged
merged 2 commits into from Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions wallet/wallet.go
Expand Up @@ -294,10 +294,11 @@ func (sw *SingleAddressWallet) FundTransaction(txn *types.Transaction, amount ty
sw.mu.Lock()
defer sw.mu.Unlock()

// remove locked and spent outputs
// remove immature, locked and spent outputs
cs := sw.cm.TipState()
utxos := make([]types.SiacoinElement, 0, len(elements))
for _, sce := range elements {
if time.Now().Before(sw.locked[sce.ID]) || tpoolSpent[sce.ID] {
if time.Now().Before(sw.locked[sce.ID]) || tpoolSpent[sce.ID] || cs.Index.Height < sce.MaturityHeight {
continue
}
utxos = append(utxos, sce.SiacoinElement)
Expand Down
32 changes: 19 additions & 13 deletions wallet/wallet_test.go
Expand Up @@ -79,10 +79,27 @@ func TestWallet(t *testing.T) {
}

// check that the wallet has an immature balance
if checkBalance(w, types.ZeroCurrency, types.ZeroCurrency, initialReward, types.ZeroCurrency); err != nil {
if err := checkBalance(w, types.ZeroCurrency, types.ZeroCurrency, initialReward, types.ZeroCurrency); err != nil {
t.Fatal(err)
}

// create a transaction that splits the wallet's balance into 20 outputs
txn := types.Transaction{
SiacoinOutputs: make([]types.SiacoinOutput, 20),
}
for i := range txn.SiacoinOutputs {
txn.SiacoinOutputs[i] = types.SiacoinOutput{
Value: initialReward.Div64(20),
Address: w.Address(),
}
}

// try funding the transaction, expect it to fail since the outputs are immature
_, err = w.FundTransaction(&txn, initialReward, false)
if err != wallet.ErrNotEnoughFunds {
t.Fatal("expected ErrNotEnoughFunds, got", err)
}

// mine until the payout matures
tip := cm.TipState()
target := tip.MaturityHeight() + 1
Expand All @@ -94,7 +111,7 @@ func TestWallet(t *testing.T) {
}

// check that one payout has matured
if checkBalance(w, initialReward, initialReward, types.ZeroCurrency, types.ZeroCurrency); err != nil {
if err := checkBalance(w, initialReward, initialReward, types.ZeroCurrency, types.ZeroCurrency); err != nil {
t.Fatal(err)
}

Expand All @@ -116,17 +133,6 @@ func TestWallet(t *testing.T) {
t.Fatalf("expected miner payout, got %v", events[0].Source)
}

// split the wallet's balance into 20 outputs
txn := types.Transaction{
SiacoinOutputs: make([]types.SiacoinOutput, 20),
}
for i := range txn.SiacoinOutputs {
txn.SiacoinOutputs[i] = types.SiacoinOutput{
Value: initialReward.Div64(20),
Address: w.Address(),
}
}

// fund and sign the transaction
toSign, err := w.FundTransaction(&txn, initialReward, false)
if err != nil {
Expand Down