Introduce new transaction store.
This change replaces the old transaction store file format and implementation. The most important change is how the full backing transactions for any received or sent transaction are now saved, rather than simply saving parsed-out details of the tx (tx shas, block height/hash, pkScripts, etc.). To support the change, notifications for received transaction outputs and txs spending watched outpoints have been updated to use the new redeemingtx and recvtx notifications as these contain the full tx, which is deserializead and inserted into the store. The old transaction store serialization code is completely removed, as updating to the new format automatically cannot be done. Old wallets first running past this change will error reading the file and start a full rescan to rebuild the data. Unlike previous rescan code, transactions spending outpoint managed by wallet are also included. This results in recovering not just received history, but history for sent transactions as well.
This commit is contained in:
parent
438f55a0a4
commit
fc2e313a39
13 changed files with 1982 additions and 2016 deletions
74
disksync.go
74
disksync.go
|
@ -91,8 +91,8 @@ func checkCreateDir(path string) error {
|
|||
}
|
||||
|
||||
// accountFilename returns the filepath of an account file given the
|
||||
// filename suffix ("wallet.bin", "tx.bin", or "utxo.bin"), account
|
||||
// name and the network directory holding the file.
|
||||
// filename suffix ("wallet.bin", or "tx.bin"), account name and the
|
||||
// network directory holding the file.
|
||||
func accountFilename(suffix, account, netdir string) string {
|
||||
if account == "" {
|
||||
// default account
|
||||
|
@ -109,7 +109,6 @@ type syncSchedule struct {
|
|||
dir string
|
||||
wallets map[*Account]struct{}
|
||||
txs map[*Account]struct{}
|
||||
utxos map[*Account]struct{}
|
||||
}
|
||||
|
||||
func newSyncSchedule(dir string) *syncSchedule {
|
||||
|
@ -117,7 +116,6 @@ func newSyncSchedule(dir string) *syncSchedule {
|
|||
dir: dir,
|
||||
wallets: make(map[*Account]struct{}),
|
||||
txs: make(map[*Account]struct{}),
|
||||
utxos: make(map[*Account]struct{}),
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
@ -125,12 +123,6 @@ func newSyncSchedule(dir string) *syncSchedule {
|
|||
// flushAccount writes all scheduled account files to disk for
|
||||
// a single account and removes them from the schedule.
|
||||
func (s *syncSchedule) flushAccount(a *Account) error {
|
||||
if _, ok := s.utxos[a]; ok {
|
||||
if err := a.writeUtxoStore(s.dir); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(s.utxos, a)
|
||||
}
|
||||
if _, ok := s.txs[a]; ok {
|
||||
if err := a.writeTxStore(s.dir); err != nil {
|
||||
return err
|
||||
|
@ -150,13 +142,6 @@ func (s *syncSchedule) flushAccount(a *Account) error {
|
|||
// flush writes all scheduled account files and removes each
|
||||
// from the schedule.
|
||||
func (s *syncSchedule) flush() error {
|
||||
for a := range s.utxos {
|
||||
if err := a.writeUtxoStore(s.dir); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(s.utxos, a)
|
||||
}
|
||||
|
||||
for a := range s.txs {
|
||||
if err := a.writeTxStore(s.dir); err != nil {
|
||||
return err
|
||||
|
@ -196,9 +181,8 @@ type DiskSyncer struct {
|
|||
flushAccount chan *flushAccountRequest
|
||||
|
||||
// Schedule file writes for an account.
|
||||
scheduleWallet chan *Account
|
||||
scheduleTxStore chan *Account
|
||||
scheduleUtxoStore chan *Account
|
||||
scheduleWallet chan *Account
|
||||
scheduleTxStore chan *Account
|
||||
|
||||
// Write a collection of accounts all at once.
|
||||
writeBatch chan *writeBatchRequest
|
||||
|
@ -214,13 +198,12 @@ type DiskSyncer struct {
|
|||
// NewDiskSyncer creates a new DiskSyncer.
|
||||
func NewDiskSyncer(am *AccountManager) *DiskSyncer {
|
||||
return &DiskSyncer{
|
||||
flushAccount: make(chan *flushAccountRequest),
|
||||
scheduleWallet: make(chan *Account),
|
||||
scheduleTxStore: make(chan *Account),
|
||||
scheduleUtxoStore: make(chan *Account),
|
||||
writeBatch: make(chan *writeBatchRequest),
|
||||
exportAccount: make(chan *exportRequest),
|
||||
am: am,
|
||||
flushAccount: make(chan *flushAccountRequest),
|
||||
scheduleWallet: make(chan *Account),
|
||||
scheduleTxStore: make(chan *Account),
|
||||
writeBatch: make(chan *writeBatchRequest),
|
||||
exportAccount: make(chan *exportRequest),
|
||||
am: am,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,12 +258,6 @@ func (ds *DiskSyncer) Start() {
|
|||
timer = time.After(wait)
|
||||
}
|
||||
|
||||
case a := <-ds.scheduleUtxoStore:
|
||||
schedule.utxos[a] = struct{}{}
|
||||
if timer == nil {
|
||||
timer = time.After(wait)
|
||||
}
|
||||
|
||||
case sr := <-ds.writeBatch:
|
||||
err := batchWriteAccounts(sr.a, tmpnetdir, netdir)
|
||||
if err == nil {
|
||||
|
@ -318,12 +295,6 @@ func (ds *DiskSyncer) ScheduleTxStoreWrite(a *Account) {
|
|||
ds.scheduleTxStore <- a
|
||||
}
|
||||
|
||||
// ScheduleUtxoStoreWrite schedules an account's utxo store to be written
|
||||
// to disk.
|
||||
func (ds *DiskSyncer) ScheduleUtxoStoreWrite(a *Account) {
|
||||
ds.scheduleUtxoStore <- a
|
||||
}
|
||||
|
||||
// WriteBatch safely replaces all account files in the network directory
|
||||
// with new files created from all accounts in a.
|
||||
func (ds *DiskSyncer) WriteBatch(a []*Account) error {
|
||||
|
@ -369,9 +340,6 @@ func batchWriteAccounts(accts []*Account, tmpdir, netdir string) error {
|
|||
}
|
||||
|
||||
func (a *Account) writeAll(dir string) error {
|
||||
if err := a.writeUtxoStore(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := a.writeTxStore(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -424,25 +392,3 @@ func (a *Account) writeTxStore(dir string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Account) writeUtxoStore(dir string) error {
|
||||
utxofilepath := accountFilename("utxo.bin", a.name, dir)
|
||||
_, filename := filepath.Split(utxofilepath)
|
||||
tmpfile, err := ioutil.TempFile(dir, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = a.UtxoStore.WriteTo(tmpfile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmppath := tmpfile.Name()
|
||||
tmpfile.Close()
|
||||
|
||||
if err = Rename(tmppath, utxofilepath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue