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

Improve wallet atomicity. #339

Merged
merged 27 commits into from
Sep 30, 2016
Merged

Improve wallet atomicity. #339

merged 27 commits into from
Sep 30, 2016

Conversation

jrick
Copy link
Member

@jrick jrick commented Sep 19, 2016

This is a step towards completing #315.

This changes the database access APIs and each of the "manager" packages (waddrmgr/wtxmgr/wstakemgr) so that transactions are opened (only) by the wallet package and the namespace buckets that each manager expects to operate on are passed in as parameters.

This helps improve the atomicity situation as it means that many calls to these APIs can be grouped together into a single database transaction.

This change does not attempt to completely fix the "half-processed" block problem. Mined transactions are still added to the wallet database under their own database transaction as this is how they are notified by the consensus JSON-RPC server (as loose transactions, without the rest of the block that contains them). It will make updating to a fixed notification model significantly easier, as the same "manager" APIs can still be used, but grouped into a single atomic transaction.

This PR requires massive testing. Nearly all parts of wallet are at least indirectly affected by this change. I can not guarantee that this will not result in a deadlock due to the changes to where transactions are opened (e.g. code inside of a write transaction may attempt to open another transaction).

Reorganize that code around to prevent a deadlock due to mixing
locking orders.  Since this mechanism has some issues, unexport it
while here so other packages don't make the same mistake.
@alexlyp
Copy link
Member

alexlyp commented Sep 26, 2016

tested thoroughly on simnet. Seeing huge increase in wallet processing.

Though there still appears to be an issue with address pool and db getting out of sync under heavy load during large amounts of autopurchasing (--enablestakemining --ticketmaxprice=20 --ticketbuyfreq=20)

@jcvernaleo
Copy link
Member

I ran this on two testnet nodes (a bitrig one that used dcrticketbuyer and an osx one that just purchased on its own) each connected to a daemon on decred/dcrd#349 (the new ticketdb) with no issues.

@jcvernaleo
Copy link
Member

I just tried a restore from seed on testnet. Took under 20 minutes on a fairly slow machine to rescan for 10888 addresses so not bad. All seems to be working after that.

@alexlyp
Copy link
Member

alexlyp commented Sep 28, 2016

Appears to have all the bugs from simnet testing shaken out.
And I have reviewed the new atomicity methodology looks great.

tACK

@jolan
Copy link
Contributor

jolan commented Sep 28, 2016

Switched over 2 of my 3 testnet stakepool wallets to this and they are voting/noticing/accepting new stake tickets OK. They're also staying in sync with the non-upgraded node. Will update if anything goes off the rails.

tACK

Copy link
Contributor

@cjepson cjepson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK after considering the comments, seems to be good from a functional standpoint.

}

_, err = w.NextAccount(cmd.Account)
_, err := w.NextAccount(cmd.Account)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You check below for if waddrmgr.IsError(err, waddrmgr.ErrLocked) { ... }, but if the error is of a different type it appears to be unhandled and overwritten.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are correct. don't think I need to say it but I am not a fan of this error model.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that's not totally true. If it's non-nil but not waddrmgr.ErrLocked, then it will still be returned with whatever the wallet fallback error code is.

@@ -1115,21 +1057,16 @@ func getNewAddress(icmd interface{}, w *wallet.Wallet) (interface{}, error) {
toReturn := make(map[string]string)
toReturn["address"] = addr.EncodeAddress()

ainfo, err := w.Manager.Address(addr)
pubKey, err := w.PubKeyForAddress(addr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you always just create a pubkey address from the pubkeys after fetching them. Why not just have a function that returns the pubkey address?

Copy link
Member Author

@jrick jrick Sep 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either can work. But if this code isn't wrong in some way, I don't see the point in changing it.

Height: 0,
}

addrInfo, err := w.Manager.ImportScript(addrmgrNs, script, bs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If ImportScript fails here due to the wallet being locked, the database update transaction where the transaction script is written to the wtxmgr will also fall through. I think the legacy methods allowed it to be written separately, but you may consider that to be a bug.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't think of any reason why you would want it added in one and not the other. Not changing this.

pkScript, err := txscript.PayToAddrScript(addr)
if err != nil {
return nil, fmt.Errorf("cannot create txout script: %s", err)
}
msgTx.AddTxOut(wire.NewTxOut(int64(toReceive), pkScript))

// Start creating the SignRawTransactionCmd.
outpointScript, err := txscript.PayToScriptHashScript(msCredit.ScriptHash[:])
outpointScript, err := txscript.PayToScriptHashScript(p2shOutput.P2SHAddress.Hash160()[:])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Hash160 instead of ScriptHash? I think they are the same thing, though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing, no reason to change it.


// Defined OutputKind constants
const (
OutputKindNormal OutputKind = iota
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OutputType maybe?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meh

// Add the address to the notifications watcher.
addrs := make([]dcrutil.Address, 1)
addrs[0] = curAddress
if err := chainClient.NotifyReceived(addrs); err != nil {
return nil, err
}

a.cursor++
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the functionality, but is correct. OK

const (
OutputKindNormal OutputKind = iota
OutputKindCoinbase
OutputKindStakebase // not returned by all APIs yet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 4x kinds of special stake outputs: OP_SSTX tagged (ticket voting rights), OP_SSGEN tagged (voting subsidy/stakebase), OP_SSRTX tagged (missed and revoked tickets), and OP_SSTXCHANGE (ticket change). Might want to have these instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm still fuzzy on the decred details here but the idea was that stakebase would be all regular tx tree coins generated due to participating in voting. I'm not sure if this type needs to represent outputs in the stake tree.

@jrick jrick merged commit db64418 into decred:master Sep 30, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants