Skip to content

Commit

Permalink
Merge pull request #723 from SiaFoundation/pj/wallet-redistribute
Browse files Browse the repository at this point in the history
Wallet Redistribute
  • Loading branch information
ChrisSchinnerl authored Nov 10, 2023
2 parents 058b1de + 778d537 commit 902fd89
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 15 deletions.
42 changes: 28 additions & 14 deletions wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,34 @@ func (w *SingleAddressWallet) Redistribute(cs consensus.State, outputs int, amou
w.mu.Lock()
defer w.mu.Unlock()

// build map of inputs currently in the tx pool
inPool := make(map[types.Hash256]bool)
for _, ptxn := range pool {
for _, in := range ptxn.SiacoinInputs {
inPool[types.Hash256(in.ParentID)] = true
}
}

// fetch unspent transaction outputs
utxos, err := w.store.UnspentSiacoinElements(false)
if err != nil {
return types.Transaction{}, nil, err
}

// check whether a redistribution is necessary, adjust number of desired
// outputs accordingly
for _, sce := range utxos {
inUse := w.isOutputUsed(sce.ID) || inPool[sce.ID]
matured := cs.Index.Height >= sce.MaturityHeight
sameValue := sce.Value.Equals(amount)
if !inUse && matured && sameValue {
outputs--
}
}
if outputs <= 0 {
return types.Transaction{}, nil, nil
}

// prepare all outputs
var txn types.Transaction
for i := 0; i < int(outputs); i++ {
Expand All @@ -313,25 +341,11 @@ func (w *SingleAddressWallet) Redistribute(cs consensus.State, outputs int, amou
})
}

// fetch unspent transaction outputs
utxos, err := w.store.UnspentSiacoinElements(false)
if err != nil {
return types.Transaction{}, nil, err
}

// desc sort
sort.Slice(utxos, func(i, j int) bool {
return utxos[i].Value.Cmp(utxos[j].Value) > 0
})

// map used outputs
inPool := make(map[types.Hash256]bool)
for _, ptxn := range pool {
for _, in := range ptxn.SiacoinInputs {
inPool[types.Hash256(in.ParentID)] = true
}
}

// estimate the fees
outputFees := feePerByte.Mul64(uint64(len(encoding.Marshal(txn.SiacoinOutputs))))
feePerInput := feePerByte.Mul64(BytesPerInput)
Expand Down
32 changes: 31 additions & 1 deletion wallet/wallet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func TestWalletRedistribute(t *testing.T) {

// split into 2 outputs of 9SC
amount = oneSC.Mul64(9)
if txn, _, err := w.Redistribute(cs, 2, oneSC.Mul64(9), types.NewCurrency64(1), nil); err != nil {
if txn, _, err := w.Redistribute(cs, 2, amount, types.NewCurrency64(1), nil); err != nil {
t.Fatal(err)
} else {
applyTxn(txn)
Expand All @@ -129,6 +129,36 @@ func TestWalletRedistribute(t *testing.T) {
if cnt := numOutputsWithValue(amount); cnt != 2 {
t.Fatalf("unexpected number of 9SC outputs, %v != 2", cnt)
}

// split into 5 outputs of 3SC
amount = oneSC.Mul64(3)
if txn, _, err := w.Redistribute(cs, 5, amount, types.NewCurrency64(1), nil); err != nil {
t.Fatal(err)
} else {
applyTxn(txn)
}

// assert number of outputs that hold 3SC
if cnt := numOutputsWithValue(amount); cnt != 5 {
t.Fatalf("unexpected number of 3SC outputs, %v != 5", cnt)
}

// split into 4 outputs of 3SC - this should be a no-op
if _, _, err := w.Redistribute(cs, 4, amount, types.NewCurrency64(1), nil); err != nil {
t.Fatal(err)
}

// split into 6 outputs of 3SC
if txn, _, err := w.Redistribute(cs, 6, amount, types.NewCurrency64(1), nil); err != nil {
t.Fatal(err)
} else {
applyTxn(txn)
}

// assert number of outputs that hold 3SC
if cnt := numOutputsWithValue(amount); cnt != 6 {
t.Fatalf("unexpected number of 3SC outputs, %v != 6", cnt)
}
}

func randomOutputID() (t types.Hash256) {
Expand Down

0 comments on commit 902fd89

Please sign in to comment.