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

Discard full txnSet and not just last txn #817

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import (
)

type (
// WalletDiscardRequest is the request type for the /wallet/discard
// endpoint.
WalletDiscardRequest struct {
TransactionSet []types.Transaction `json:"transactionSet"`
}

// WalletFundRequest is the request type for the /wallet/fund endpoint.
WalletFundRequest struct {
Transaction types.Transaction `json:"transaction"`
Expand Down
2 changes: 1 addition & 1 deletion autopilot/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ type Bus interface {

// wallet
Wallet(ctx context.Context) (api.WalletResponse, error)
WalletDiscard(ctx context.Context, txn types.Transaction) error
WalletDiscard(ctx context.Context, txnSet ...types.Transaction) error
WalletOutputs(ctx context.Context) (resp []wallet.SiacoinElement, err error)
WalletPending(ctx context.Context) (resp []types.Transaction, err error)
WalletRedistribute(ctx context.Context, outputs int, amount types.Currency) (id types.TransactionID, err error)
Expand Down
8 changes: 4 additions & 4 deletions bus/bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ type (
FundTransaction(cs consensus.State, txn *types.Transaction, amount types.Currency, useUnconfirmedTxns bool) ([]types.Hash256, error)
Height() uint64
Redistribute(cs consensus.State, outputs int, amount, feePerByte types.Currency, pool []types.Transaction) (types.Transaction, []types.Hash256, error)
ReleaseInputs(txn types.Transaction)
ReleaseInputs(txnSet ...types.Transaction)
SignTransaction(cs consensus.State, txn *types.Transaction, toSign []types.Hash256, cf types.CoveredFields) error
Transactions(before, since time.Time, offset, limit int) ([]wallet.Transaction, error)
UnspentOutputs() ([]wallet.SiacoinElement, error)
Expand Down Expand Up @@ -621,9 +621,9 @@ func (b *bus) walletRedistributeHandler(jc jape.Context) {
}

func (b *bus) walletDiscardHandler(jc jape.Context) {
var txn types.Transaction
if jc.Decode(&txn) == nil {
b.w.ReleaseInputs(txn)
var wdr api.WalletDiscardRequest
if jc.Decode(&wdr) == nil {
b.w.ReleaseInputs(wdr.TransactionSet...)
}
}

Expand Down
13 changes: 8 additions & 5 deletions bus/client/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@ func (c *Client) SendSiacoins(ctx context.Context, scos []types.SiacoinOutput, u
if err != nil {
return err
}
txnSet := append(parents, txn)
defer func() {
if err != nil {
_ = c.WalletDiscard(ctx, txn)
_ = c.WalletDiscard(ctx, txnSet...)
}
}()
err = c.WalletSign(ctx, &txn, toSign, types.CoveredFields{WholeTransaction: true})
err = c.WalletSign(ctx, &txnSet[len(txnSet)-1], toSign, types.CoveredFields{WholeTransaction: true})
if err != nil {
return err
}
return c.BroadcastTransaction(ctx, append(parents, txn))
return c.BroadcastTransaction(ctx, txnSet)
}

// Wallet calls the /wallet endpoint on the bus.
Expand All @@ -46,8 +47,10 @@ func (c *Client) Wallet(ctx context.Context) (resp api.WalletResponse, err error

// WalletDiscard discards the provided txn, make its inputs usable again. This
// should only be called on transactions that will never be broadcast.
func (c *Client) WalletDiscard(ctx context.Context, txn types.Transaction) error {
return c.c.WithContext(ctx).POST("/wallet/discard", txn, nil)
func (c *Client) WalletDiscard(ctx context.Context, txn ...types.Transaction) error {
return c.c.WithContext(ctx).POST("/wallet/discard", api.WalletDiscardRequest{
TransactionSet: txn,
}, nil)
}

// WalletFund funds txn using inputs controlled by the wallet.
Expand Down
8 changes: 5 additions & 3 deletions wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,11 @@ func (w *SingleAddressWallet) FundTransaction(cs consensus.State, txn *types.Tra
// ReleaseInputs is a helper function that releases the inputs of txn for use in
// other transactions. It should only be called on transactions that are invalid
// or will never be broadcast.
func (w *SingleAddressWallet) ReleaseInputs(txn types.Transaction) {
for _, in := range txn.SiacoinInputs {
delete(w.lastUsed, types.Hash256(in.ParentID))
func (w *SingleAddressWallet) ReleaseInputs(txnSet ...types.Transaction) {
for _, txn := range txnSet {
for _, in := range txn.SiacoinInputs {
delete(w.lastUsed, types.Hash256(in.ParentID))
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion worker/rhpv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -1231,7 +1231,7 @@ func RPCRenew(ctx context.Context, rrr api.RHPRenewRequest, bus Bus, t *transpor
}

// Starting from here, we need to make sure to release the txn on error.
defer discardTxnOnErr(ctx, bus, l, wprr.TransactionSet[len(wprr.TransactionSet)-1], "RPCRenew", &err)
defer discardTxnSetOnErr(ctx, bus, l, wprr.TransactionSet, "RPCRenew", &err)

txnSet := wprr.TransactionSet
parents, txn := txnSet[:len(txnSet)-1], txnSet[len(txnSet)-1]
Expand Down
20 changes: 11 additions & 9 deletions worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ type (
MultipartUpload(ctx context.Context, uploadID string) (resp api.MultipartUpload, err error)
PackedSlabsForUpload(ctx context.Context, lockingDuration time.Duration, minShards, totalShards uint8, set string, limit int) ([]api.PackedSlab, error)

WalletDiscard(ctx context.Context, txn types.Transaction) error
WalletDiscard(ctx context.Context, txnSet ...types.Transaction) error
WalletFund(ctx context.Context, txn *types.Transaction, amount types.Currency, useUnconfirmedTxns bool) ([]types.Hash256, []types.Transaction, error)
WalletPrepareForm(ctx context.Context, renterAddress types.Address, renterKey types.PublicKey, renterFunds, hostCollateral types.Currency, hostKey types.PublicKey, hostSettings rhpv2.HostSettings, endHeight uint64) (txns []types.Transaction, err error)
WalletPrepareRenew(ctx context.Context, revision types.FileContractRevision, hostAddress, renterAddress types.Address, renterKey types.PrivateKey, renterFunds, minNewCollateral types.Currency, pt rhpv3.HostPriceTable, endHeight, windowSize, expectedStorage uint64) (api.WalletPrepareRenewResponse, error)
Expand Down Expand Up @@ -373,8 +373,8 @@ func (w *worker) rhpPriceTableHandler(jc jape.Context) {
jc.Encode(hpt)
}

func (w *worker) discardTxnOnErr(ctx context.Context, txn types.Transaction, errContext string, err *error) {
discardTxnOnErr(ctx, w.bus, w.logger, txn, errContext, err)
func (w *worker) discardTxnSetOnErr(ctx context.Context, txnSet []types.Transaction, errContext string, err *error) {
discardTxnSetOnErr(ctx, w.bus, w.logger, txnSet, errContext, err)
}

func (w *worker) rhpFormHandler(jc jape.Context) {
Expand Down Expand Up @@ -429,7 +429,7 @@ func (w *worker) rhpFormHandler(jc jape.Context) {
if err != nil {
return err
}
defer w.discardTxnOnErr(ctx, renterTxnSet[len(renterTxnSet)-1], "rhpFormHandler", &err)
defer w.discardTxnSetOnErr(ctx, renterTxnSet, "rhpFormHandler", &err)

contract, txnSet, err = RPCFormContract(ctx, t, renterKey, renterTxnSet)
if err != nil {
Expand Down Expand Up @@ -492,19 +492,21 @@ func (w *worker) rhpBroadcastHandler(jc jape.Context) {
if jc.Check("failed to fund transaction", err) != nil {
return
}

// Sign the txn.
err = w.bus.WalletSign(ctx, &txn, toSign, types.CoveredFields{
WholeTransaction: true,
})

txnSet := append(parents, txn)
if jc.Check("failed to sign transaction", err) != nil {
_ = w.bus.WalletDiscard(ctx, txn)
_ = w.bus.WalletDiscard(ctx, txnSet...)
return
}
// Broadcast the txn.
txnSet := append(parents, txn)
err = w.bus.BroadcastTransaction(ctx, txnSet)
if jc.Check("failed to broadcast transaction", err) != nil {
_ = w.bus.WalletDiscard(ctx, txn)
_ = w.bus.WalletDiscard(ctx, txnSet...)
return
}
}
Expand Down Expand Up @@ -1420,7 +1422,7 @@ func (w *worker) scanHost(ctx context.Context, hostKey types.PublicKey, hostIP s
return
}

func discardTxnOnErr(ctx context.Context, bus Bus, l *zap.SugaredLogger, txn types.Transaction, errContext string, err *error) {
func discardTxnSetOnErr(ctx context.Context, bus Bus, l *zap.SugaredLogger, txnSet []types.Transaction, errContext string, err *error) {
if *err == nil {
return
}
Expand All @@ -1430,7 +1432,7 @@ func discardTxnOnErr(ctx context.Context, bus Bus, l *zap.SugaredLogger, txn typ
timeoutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
timeoutCtx = trace.ContextWithSpan(timeoutCtx, span)
if err := bus.WalletDiscard(timeoutCtx, txn); err != nil {
if err := bus.WalletDiscard(timeoutCtx, txnSet...); err != nil {
l.Errorf("%v: failed to discard txn: %v", err)
}
}
Expand Down