From f143d095d65623a45b48bf79381e7b85ea060762 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Wed, 18 Jan 2017 15:29:34 -0500 Subject: [PATCH] Make votingpool package (sans tests) compile --- votingpool/db.go | 53 +++++++------ votingpool/input_selection.go | 27 +++---- votingpool/pool.go | 139 +++++++++++++--------------------- votingpool/withdrawal.go | 51 +++++-------- 4 files changed, 113 insertions(+), 157 deletions(-) diff --git a/votingpool/db.go b/votingpool/db.go index 62a1f9f..acb3320 100644 --- a/votingpool/db.go +++ b/votingpool/db.go @@ -117,10 +117,10 @@ func getUsedAddrBucketID(seriesID uint32, branch Branch) []byte { // putUsedAddrHash adds an entry (key==index, value==encryptedHash) to the used // addresses bucket of the given pool, series and branch. -func putUsedAddrHash(tx walletdb.Tx, poolID []byte, seriesID uint32, branch Branch, +func putUsedAddrHash(ns walletdb.ReadWriteBucket, poolID []byte, seriesID uint32, branch Branch, index Index, encryptedHash []byte) error { - usedAddrs := tx.RootBucket().Bucket(poolID).Bucket(usedAddrsBucketName) + usedAddrs := ns.NestedReadWriteBucket(poolID).NestedReadWriteBucket(usedAddrsBucketName) bucket, err := usedAddrs.CreateBucketIfNotExists(getUsedAddrBucketID(seriesID, branch)) if err != nil { return newError(ErrDatabase, "failed to store used address hash", err) @@ -130,11 +130,11 @@ func putUsedAddrHash(tx walletdb.Tx, poolID []byte, seriesID uint32, branch Bran // getUsedAddrHash returns the addr hash with the given index from the used // addresses bucket of the given pool, series and branch. -func getUsedAddrHash(tx walletdb.Tx, poolID []byte, seriesID uint32, branch Branch, +func getUsedAddrHash(ns walletdb.ReadBucket, poolID []byte, seriesID uint32, branch Branch, index Index) []byte { - usedAddrs := tx.RootBucket().Bucket(poolID).Bucket(usedAddrsBucketName) - bucket := usedAddrs.Bucket(getUsedAddrBucketID(seriesID, branch)) + usedAddrs := ns.NestedReadBucket(poolID).NestedReadBucket(usedAddrsBucketName) + bucket := usedAddrs.NestedReadBucket(getUsedAddrBucketID(seriesID, branch)) if bucket == nil { return nil } @@ -143,10 +143,10 @@ func getUsedAddrHash(tx walletdb.Tx, poolID []byte, seriesID uint32, branch Bran // getMaxUsedIdx returns the highest used index from the used addresses bucket // of the given pool, series and branch. -func getMaxUsedIdx(tx walletdb.Tx, poolID []byte, seriesID uint32, branch Branch) (Index, error) { +func getMaxUsedIdx(ns walletdb.ReadBucket, poolID []byte, seriesID uint32, branch Branch) (Index, error) { maxIdx := Index(0) - usedAddrs := tx.RootBucket().Bucket(poolID).Bucket(usedAddrsBucketName) - bucket := usedAddrs.Bucket(getUsedAddrBucketID(seriesID, branch)) + usedAddrs := ns.NestedReadBucket(poolID).NestedReadBucket(usedAddrsBucketName) + bucket := usedAddrs.NestedReadBucket(getUsedAddrBucketID(seriesID, branch)) if bucket == nil { return maxIdx, nil } @@ -173,8 +173,8 @@ func getMaxUsedIdx(tx walletdb.Tx, poolID []byte, seriesID uint32, branch Branch // putPool stores a voting pool in the database, creating a bucket named // after the voting pool id and two other buckets inside it to store series and // used addresses for that pool. -func putPool(tx walletdb.Tx, poolID []byte) error { - poolBucket, err := tx.RootBucket().CreateBucket(poolID) +func putPool(ns walletdb.ReadWriteBucket, poolID []byte) error { + poolBucket, err := ns.CreateBucket(poolID) if err != nil { return newError(ErrDatabase, fmt.Sprintf("cannot create pool %v", poolID), err) } @@ -198,8 +198,8 @@ func putPool(tx walletdb.Tx, poolID []byte) error { // loadAllSeries returns a map of all the series stored inside a voting pool // bucket, keyed by id. -func loadAllSeries(tx walletdb.Tx, poolID []byte) (map[uint32]*dbSeriesRow, error) { - bucket := tx.RootBucket().Bucket(poolID).Bucket(seriesBucketName) +func loadAllSeries(ns walletdb.ReadBucket, poolID []byte) (map[uint32]*dbSeriesRow, error) { + bucket := ns.NestedReadBucket(poolID).NestedReadBucket(seriesBucketName) allSeries := make(map[uint32]*dbSeriesRow) err := bucket.ForEach( func(k, v []byte) error { @@ -219,14 +219,14 @@ func loadAllSeries(tx walletdb.Tx, poolID []byte) (map[uint32]*dbSeriesRow, erro // existsPool checks the existence of a bucket named after the given // voting pool id. -func existsPool(tx walletdb.Tx, poolID []byte) bool { - bucket := tx.RootBucket().Bucket(poolID) +func existsPool(ns walletdb.ReadBucket, poolID []byte) bool { + bucket := ns.NestedReadBucket(poolID) return bucket != nil } // putSeries stores the given series inside a voting pool bucket named after // poolID. The voting pool bucket does not need to be created beforehand. -func putSeries(tx walletdb.Tx, poolID []byte, version, ID uint32, active bool, reqSigs uint32, pubKeysEncrypted, privKeysEncrypted [][]byte) error { +func putSeries(ns walletdb.ReadWriteBucket, poolID []byte, version, ID uint32, active bool, reqSigs uint32, pubKeysEncrypted, privKeysEncrypted [][]byte) error { row := &dbSeriesRow{ version: version, active: active, @@ -234,19 +234,22 @@ func putSeries(tx walletdb.Tx, poolID []byte, version, ID uint32, active bool, r pubKeysEncrypted: pubKeysEncrypted, privKeysEncrypted: privKeysEncrypted, } - return putSeriesRow(tx, poolID, ID, row) + return putSeriesRow(ns, poolID, ID, row) } // putSeriesRow stores the given series row inside a voting pool bucket named // after poolID. The voting pool bucket does not need to be created // beforehand. -func putSeriesRow(tx walletdb.Tx, poolID []byte, ID uint32, row *dbSeriesRow) error { - bucket, err := tx.RootBucket().CreateBucketIfNotExists(poolID) +func putSeriesRow(ns walletdb.ReadWriteBucket, poolID []byte, ID uint32, row *dbSeriesRow) error { + bucket, err := ns.CreateBucketIfNotExists(poolID) if err != nil { str := fmt.Sprintf("cannot create bucket %v", poolID) return newError(ErrDatabase, str, err) } - bucket = bucket.Bucket(seriesBucketName) + bucket, err = bucket.CreateBucketIfNotExists(seriesBucketName) + if err != nil { + return err + } serialized, err := serializeSeriesRow(row) if err != nil { return err @@ -473,7 +476,7 @@ func serializeWithdrawal(requests []OutputRequest, startAddress WithdrawalAddres // deserializeWithdrawal deserializes the given byte slice into a dbWithdrawalRow, // converts it into an withdrawalInfo and returns it. This function must run // with the address manager unlocked. -func deserializeWithdrawal(p *Pool, serialized []byte) (*withdrawalInfo, error) { +func deserializeWithdrawal(p *Pool, ns, addrmgrNs walletdb.ReadBucket, serialized []byte) (*withdrawalInfo, error) { var row dbWithdrawalRow if err := gob.NewDecoder(bytes.NewReader(serialized)).Decode(&row); err != nil { return nil, newError(ErrWithdrawalStorage, "cannot deserialize withdrawal information", @@ -509,7 +512,7 @@ func deserializeWithdrawal(p *Pool, serialized []byte) (*withdrawalInfo, error) requestsByOID[request.outBailmentID()] = request } startAddr := row.StartAddress - wAddr, err := p.WithdrawalAddress(startAddr.SeriesID, startAddr.Branch, startAddr.Index) + wAddr, err := p.WithdrawalAddress(ns, addrmgrNs, startAddr.SeriesID, startAddr.Branch, startAddr.Index) if err != nil { return nil, newError(ErrWithdrawalStorage, "cannot deserialize startAddress", err) } @@ -564,13 +567,13 @@ func deserializeWithdrawal(p *Pool, serialized []byte) (*withdrawalInfo, error) return wInfo, nil } -func putWithdrawal(tx walletdb.Tx, poolID []byte, roundID uint32, serialized []byte) error { - bucket := tx.RootBucket().Bucket(poolID) +func putWithdrawal(ns walletdb.ReadWriteBucket, poolID []byte, roundID uint32, serialized []byte) error { + bucket := ns.NestedReadWriteBucket(poolID) return bucket.Put(uint32ToBytes(roundID), serialized) } -func getWithdrawal(tx walletdb.Tx, poolID []byte, roundID uint32) []byte { - bucket := tx.RootBucket().Bucket(poolID) +func getWithdrawal(ns walletdb.ReadBucket, poolID []byte, roundID uint32) []byte { + bucket := ns.NestedReadBucket(poolID) return bucket.Get(uint32ToBytes(roundID)) } diff --git a/votingpool/input_selection.go b/votingpool/input_selection.go index 511bea8..39cbe34 100644 --- a/votingpool/input_selection.go +++ b/votingpool/input_selection.go @@ -21,10 +21,11 @@ import ( "fmt" "sort" - "github.com/roasbeef/btcd/chaincfg" - "github.com/roasbeef/btcd/txscript" - "github.com/roasbeef/btcutil" - "github.com/roasbeef/btcwallet/wtxmgr" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcwallet/walletdb" + "github.com/btcsuite/btcwallet/wtxmgr" ) const eligibleInputMinConfirmations = 100 @@ -98,7 +99,7 @@ func (c byAddress) Less(i, j int) bool { // getEligibleInputs returns eligible inputs with addresses between startAddress // and the last used address of lastSeriesID. They're reverse ordered based on // their address. -func (p *Pool) getEligibleInputs(store *wtxmgr.Store, startAddress WithdrawalAddress, +func (p *Pool) getEligibleInputs(ns, addrmgrNs walletdb.ReadBucket, store *wtxmgr.Store, txmgrNs walletdb.ReadBucket, startAddress WithdrawalAddress, lastSeriesID uint32, dustThreshold btcutil.Amount, chainHeight int32, minConf int) ([]credit, error) { @@ -106,7 +107,7 @@ func (p *Pool) getEligibleInputs(store *wtxmgr.Store, startAddress WithdrawalAdd str := fmt.Sprintf("lastSeriesID (%d) does not exist", lastSeriesID) return nil, newError(ErrSeriesNotExists, str, nil) } - unspents, err := store.UnspentOutputs() + unspents, err := store.UnspentOutputs(txmgrNs) if err != nil { return nil, newError(ErrInputSelection, "failed to get unspent outputs", err) } @@ -128,7 +129,7 @@ func (p *Pool) getEligibleInputs(store *wtxmgr.Store, startAddress WithdrawalAdd } inputs = append(inputs, eligibles...) } - nAddr, err := nextAddr(p, address.seriesID, address.branch, address.index, lastSeriesID+1) + nAddr, err := nextAddr(p, ns, addrmgrNs, address.seriesID, address.branch, address.index, lastSeriesID+1) if err != nil { return nil, newError(ErrInputSelection, "failed to get next withdrawal address", err) } else if nAddr == nil { @@ -144,7 +145,7 @@ func (p *Pool) getEligibleInputs(store *wtxmgr.Store, startAddress WithdrawalAdd // nextAddr returns the next WithdrawalAddress according to the input selection // rules: http://opentransactions.org/wiki/index.php/Input_Selection_Algorithm_(voting_pools) // It returns nil if the new address' seriesID is >= stopSeriesID. -func nextAddr(p *Pool, seriesID uint32, branch Branch, index Index, stopSeriesID uint32) ( +func nextAddr(p *Pool, ns, addrmgrNs walletdb.ReadBucket, seriesID uint32, branch Branch, index Index, stopSeriesID uint32) ( *WithdrawalAddress, error) { series := p.Series(seriesID) if series == nil { @@ -152,7 +153,7 @@ func nextAddr(p *Pool, seriesID uint32, branch Branch, index Index, stopSeriesID } branch++ if int(branch) > len(series.publicKeys) { - highestIdx, err := p.highestUsedSeriesIndex(seriesID) + highestIdx, err := p.highestUsedSeriesIndex(ns, seriesID) if err != nil { return nil, err } @@ -171,14 +172,14 @@ func nextAddr(p *Pool, seriesID uint32, branch Branch, index Index, stopSeriesID return nil, nil } - addr, err := p.WithdrawalAddress(seriesID, branch, index) + addr, err := p.WithdrawalAddress(ns, addrmgrNs, seriesID, branch, index) if err != nil && err.(Error).ErrorCode == ErrWithdrawFromUnusedAddr { // The used indices will vary between branches so sometimes we'll try to // get a WithdrawalAddress that hasn't been used before, and in such // cases we just need to move on to the next one. log.Debugf("nextAddr(): skipping addr (series #%d, branch #%d, index #%d) as it hasn't "+ "been used before", seriesID, branch, index) - return nextAddr(p, seriesID, branch, index, stopSeriesID) + return nextAddr(p, ns, addrmgrNs, seriesID, branch, index, stopSeriesID) } return addr, err } @@ -186,7 +187,7 @@ func nextAddr(p *Pool, seriesID uint32, branch Branch, index Index, stopSeriesID // highestUsedSeriesIndex returns the highest index among all of this Pool's // used addresses for the given seriesID. It returns 0 if there are no used // addresses with the given seriesID. -func (p *Pool) highestUsedSeriesIndex(seriesID uint32) (Index, error) { +func (p *Pool) highestUsedSeriesIndex(ns walletdb.ReadBucket, seriesID uint32) (Index, error) { maxIdx := Index(0) series := p.Series(seriesID) if series == nil { @@ -194,7 +195,7 @@ func (p *Pool) highestUsedSeriesIndex(seriesID uint32) (Index, error) { newError(ErrSeriesNotExists, fmt.Sprintf("unknown seriesID: %d", seriesID), nil) } for i := range series.publicKeys { - idx, err := p.highestUsedIndexFor(seriesID, Branch(i)) + idx, err := p.highestUsedIndexFor(ns, seriesID, Branch(i)) if err != nil { return Index(0), err } diff --git a/votingpool/pool.go b/votingpool/pool.go index d85264c..d8d2354 100644 --- a/votingpool/pool.go +++ b/votingpool/pool.go @@ -48,7 +48,6 @@ type Pool struct { ID []byte seriesLookup map[uint32]*SeriesData manager *waddrmgr.Manager - namespace walletdb.Namespace } // PoolAddress represents a voting pool P2SH address, generated by @@ -83,54 +82,43 @@ type WithdrawalAddress struct { // Create creates a new entry in the database with the given ID // and returns the Pool representing it. -func Create(namespace walletdb.Namespace, m *waddrmgr.Manager, poolID []byte) (*Pool, error) { - err := namespace.Update( - func(tx walletdb.Tx) error { - return putPool(tx, poolID) - }) +func Create(ns walletdb.ReadWriteBucket, m *waddrmgr.Manager, poolID []byte) (*Pool, error) { + err := putPool(ns, poolID) if err != nil { str := fmt.Sprintf("unable to add voting pool %v to db", poolID) return nil, newError(ErrPoolAlreadyExists, str, err) } - return newPool(namespace, m, poolID), nil + return newPool(m, poolID), nil } // Load fetches the entry in the database with the given ID and returns the Pool // representing it. -func Load(namespace walletdb.Namespace, m *waddrmgr.Manager, poolID []byte) (*Pool, error) { - err := namespace.View( - func(tx walletdb.Tx) error { - if exists := existsPool(tx, poolID); !exists { - str := fmt.Sprintf("unable to find voting pool %v in db", poolID) - return newError(ErrPoolNotExists, str, nil) - } - return nil - }) - if err != nil { - return nil, err +func Load(ns walletdb.ReadBucket, m *waddrmgr.Manager, poolID []byte) (*Pool, error) { + if !existsPool(ns, poolID) { + str := fmt.Sprintf("unable to find voting pool %v in db", poolID) + return nil, newError(ErrPoolNotExists, str, nil) } - p := newPool(namespace, m, poolID) - if err = p.LoadAllSeries(); err != nil { + p := newPool(m, poolID) + if err := p.LoadAllSeries(ns); err != nil { return nil, err } return p, nil } // newPool creates a new Pool instance. -func newPool(namespace walletdb.Namespace, m *waddrmgr.Manager, poolID []byte) *Pool { +func newPool(m *waddrmgr.Manager, poolID []byte) *Pool { return &Pool{ ID: poolID, seriesLookup: make(map[uint32]*SeriesData), manager: m, - namespace: namespace, } } // LoadAndGetDepositScript generates and returns a deposit script for the given seriesID, // branch and index of the Pool identified by poolID. -func LoadAndGetDepositScript(namespace walletdb.Namespace, m *waddrmgr.Manager, poolID string, seriesID uint32, branch Branch, index Index) ([]byte, error) { +func LoadAndGetDepositScript(ns walletdb.ReadBucket, m *waddrmgr.Manager, poolID string, seriesID uint32, branch Branch, index Index) ([]byte, error) { pid := []byte(poolID) - p, err := Load(namespace, m, pid) + p, err := Load(ns, m, pid) if err != nil { return nil, err } @@ -144,14 +132,14 @@ func LoadAndGetDepositScript(namespace walletdb.Namespace, m *waddrmgr.Manager, // LoadAndCreateSeries loads the Pool with the given ID, creating a new one if it doesn't // yet exist, and then creates and returns a Series with the given seriesID, rawPubKeys // and reqSigs. See CreateSeries for the constraints enforced on rawPubKeys and reqSigs. -func LoadAndCreateSeries(namespace walletdb.Namespace, m *waddrmgr.Manager, version uint32, +func LoadAndCreateSeries(ns walletdb.ReadWriteBucket, m *waddrmgr.Manager, version uint32, poolID string, seriesID, reqSigs uint32, rawPubKeys []string) error { pid := []byte(poolID) - p, err := Load(namespace, m, pid) + p, err := Load(ns, m, pid) if err != nil { vpErr := err.(Error) if vpErr.ErrorCode == ErrPoolNotExists { - p, err = Create(namespace, m, pid) + p, err = Create(ns, m, pid) if err != nil { return err } @@ -159,31 +147,31 @@ func LoadAndCreateSeries(namespace walletdb.Namespace, m *waddrmgr.Manager, vers return err } } - return p.CreateSeries(version, seriesID, reqSigs, rawPubKeys) + return p.CreateSeries(ns, version, seriesID, reqSigs, rawPubKeys) } // LoadAndReplaceSeries loads the voting pool with the given ID and calls ReplaceSeries, // passing the given series ID, public keys and reqSigs to it. -func LoadAndReplaceSeries(namespace walletdb.Namespace, m *waddrmgr.Manager, version uint32, +func LoadAndReplaceSeries(ns walletdb.ReadWriteBucket, m *waddrmgr.Manager, version uint32, poolID string, seriesID, reqSigs uint32, rawPubKeys []string) error { pid := []byte(poolID) - p, err := Load(namespace, m, pid) + p, err := Load(ns, m, pid) if err != nil { return err } - return p.ReplaceSeries(version, seriesID, reqSigs, rawPubKeys) + return p.ReplaceSeries(ns, version, seriesID, reqSigs, rawPubKeys) } // LoadAndEmpowerSeries loads the voting pool with the given ID and calls EmpowerSeries, // passing the given series ID and private key to it. -func LoadAndEmpowerSeries(namespace walletdb.Namespace, m *waddrmgr.Manager, +func LoadAndEmpowerSeries(ns walletdb.ReadWriteBucket, m *waddrmgr.Manager, poolID string, seriesID uint32, rawPrivKey string) error { pid := []byte(poolID) - pool, err := Load(namespace, m, pid) + pool, err := Load(ns, m, pid) if err != nil { return err } - return pool.EmpowerSeries(seriesID, rawPrivKey) + return pool.EmpowerSeries(ns, seriesID, rawPrivKey) } // Series returns the series with the given ID, or nil if it doesn't @@ -205,7 +193,7 @@ func (p *Pool) Manager() *waddrmgr.Manager { // first encrypting the public/private extended keys. // // This method must be called with the Pool's manager unlocked. -func (p *Pool) saveSeriesToDisk(seriesID uint32, data *SeriesData) error { +func (p *Pool) saveSeriesToDisk(ns walletdb.ReadWriteBucket, seriesID uint32, data *SeriesData) error { var err error encryptedPubKeys := make([][]byte, len(data.publicKeys)) for i, pubKey := range data.publicKeys { @@ -230,10 +218,8 @@ func (p *Pool) saveSeriesToDisk(seriesID uint32, data *SeriesData) error { } } - err = p.namespace.Update(func(tx walletdb.Tx) error { - return putSeries(tx, p.ID, data.version, seriesID, data.active, - data.reqSigs, encryptedPubKeys, encryptedPrivKeys) - }) + err = putSeries(ns, p.ID, data.version, seriesID, data.active, + data.reqSigs, encryptedPubKeys, encryptedPrivKeys) if err != nil { str := fmt.Sprintf("cannot put series #%d into db", seriesID) return newError(ErrSeriesSerialization, str, err) @@ -286,7 +272,7 @@ func convertAndValidatePubKeys(rawPubKeys []string) ([]*hdkeychain.ExtendedKey, // inRawPubKeys. // // This method must be called with the Pool's manager unlocked. -func (p *Pool) putSeries(version, seriesID, reqSigs uint32, inRawPubKeys []string) error { +func (p *Pool) putSeries(ns walletdb.ReadWriteBucket, version, seriesID, reqSigs uint32, inRawPubKeys []string) error { if len(inRawPubKeys) < minSeriesPubKeys { str := fmt.Sprintf("need at least %d public keys to create a series", minSeriesPubKeys) return newError(ErrTooFewPublicKeys, str, nil) @@ -313,7 +299,7 @@ func (p *Pool) putSeries(version, seriesID, reqSigs uint32, inRawPubKeys []strin privateKeys: make([]*hdkeychain.ExtendedKey, len(keys)), } - err = p.saveSeriesToDisk(seriesID, data) + err = p.saveSeriesToDisk(ns, seriesID, data) if err != nil { return err } @@ -326,7 +312,7 @@ func (p *Pool) putSeries(version, seriesID, reqSigs uint32, inRawPubKeys []strin // - seriesID must be greater than or equal 1; // - rawPubKeys has to contain three or more public keys; // - reqSigs has to be less or equal than the number of public keys in rawPubKeys. -func (p *Pool) CreateSeries(version, seriesID, reqSigs uint32, rawPubKeys []string) error { +func (p *Pool) CreateSeries(ns walletdb.ReadWriteBucket, version, seriesID, reqSigs uint32, rawPubKeys []string) error { if seriesID == 0 { return newError(ErrSeriesIDInvalid, "series ID cannot be 0", nil) } @@ -344,18 +330,18 @@ func (p *Pool) CreateSeries(version, seriesID, reqSigs uint32, rawPubKeys []stri } } - return p.putSeries(version, seriesID, reqSigs, rawPubKeys) + return p.putSeries(ns, version, seriesID, reqSigs, rawPubKeys) } // ActivateSeries marks the series with the given ID as active. -func (p *Pool) ActivateSeries(seriesID uint32) error { +func (p *Pool) ActivateSeries(ns walletdb.ReadWriteBucket, seriesID uint32) error { series := p.Series(seriesID) if series == nil { str := fmt.Sprintf("series #%d does not exist, cannot activate it", seriesID) return newError(ErrSeriesNotExists, str, nil) } series.active = true - err := p.saveSeriesToDisk(seriesID, series) + err := p.saveSeriesToDisk(ns, seriesID, series) if err != nil { return err } @@ -367,7 +353,7 @@ func (p *Pool) ActivateSeries(seriesID uint32) error { // // - rawPubKeys has to contain three or more public keys // - reqSigs has to be less or equal than the number of public keys in rawPubKeys. -func (p *Pool) ReplaceSeries(version, seriesID, reqSigs uint32, rawPubKeys []string) error { +func (p *Pool) ReplaceSeries(ns walletdb.ReadWriteBucket, version, seriesID, reqSigs uint32, rawPubKeys []string) error { series := p.Series(seriesID) if series == nil { str := fmt.Sprintf("series #%d does not exist, cannot replace it", seriesID) @@ -379,7 +365,7 @@ func (p *Pool) ReplaceSeries(version, seriesID, reqSigs uint32, rawPubKeys []str return newError(ErrSeriesAlreadyEmpowered, str, nil) } - return p.putSeries(version, seriesID, reqSigs, rawPubKeys) + return p.putSeries(ns, version, seriesID, reqSigs, rawPubKeys) } // decryptExtendedKey uses Manager.Decrypt() to decrypt the encrypted byte slice and return @@ -459,13 +445,8 @@ func validateAndDecryptKeys(rawPubKeys, rawPrivKeys [][]byte, p *Pool) (pubKeys, // This method must be called with the Pool's manager unlocked. // FIXME: We should be able to get rid of this (and loadAllSeries/seriesLookup) // by making Series() load the series data directly from the DB. -func (p *Pool) LoadAllSeries() error { - var series map[uint32]*dbSeriesRow - err := p.namespace.View(func(tx walletdb.Tx) error { - var err error - series, err = loadAllSeries(tx, p.ID) - return err - }) +func (p *Pool) LoadAllSeries(ns walletdb.ReadBucket) error { + series, err := loadAllSeries(ns, p.ID) if err != nil { return err } @@ -620,10 +601,10 @@ func (p *Pool) ChangeAddress(seriesID uint32, index Index) (*ChangeAddress, erro // processing withdrawals we may iterate over a huge number of addresses and // it'd be too expensive to re-generate the redeem script for all of them. // This method must be called with the manager unlocked. -func (p *Pool) WithdrawalAddress(seriesID uint32, branch Branch, index Index) ( +func (p *Pool) WithdrawalAddress(ns, addrmgrNs walletdb.ReadBucket, seriesID uint32, branch Branch, index Index) ( *WithdrawalAddress, error) { // TODO: Ensure the given series is hot. - addr, err := p.getUsedAddr(seriesID, branch, index) + addr, err := p.getUsedAddr(ns, addrmgrNs, seriesID, branch, index) if err != nil { return nil, err } @@ -661,7 +642,7 @@ func (p *Pool) poolAddress(seriesID uint32, branch Branch, index Index, script [ // private extended key and must match one of the series' extended public keys. // // This method must be called with the Pool's manager unlocked. -func (p *Pool) EmpowerSeries(seriesID uint32, rawPrivKey string) error { +func (p *Pool) EmpowerSeries(ns walletdb.ReadWriteBucket, seriesID uint32, rawPrivKey string) error { // make sure this series exists series := p.Series(seriesID) if series == nil { @@ -708,7 +689,7 @@ func (p *Pool) EmpowerSeries(seriesID uint32, rawPrivKey string) error { return newError(ErrKeysPrivatePublicMismatch, str, nil) } - if err = p.saveSeriesToDisk(seriesID, series); err != nil { + if err = p.saveSeriesToDisk(ns, seriesID, series); err != nil { return err } @@ -718,8 +699,8 @@ func (p *Pool) EmpowerSeries(seriesID uint32, rawPrivKey string) error { // EnsureUsedAddr ensures we have entries in our used addresses DB for the given // seriesID, branch and all indices up to the given one. It must be called with // the manager unlocked. -func (p *Pool) EnsureUsedAddr(seriesID uint32, branch Branch, index Index) error { - lastIdx, err := p.highestUsedIndexFor(seriesID, branch) +func (p *Pool) EnsureUsedAddr(ns, addrmgrNs walletdb.ReadWriteBucket, seriesID uint32, branch Branch, index Index) error { + lastIdx, err := p.highestUsedIndexFor(ns, seriesID, branch) if err != nil { return err } @@ -727,13 +708,13 @@ func (p *Pool) EnsureUsedAddr(seriesID uint32, branch Branch, index Index) error // highestUsedIndexFor() returns 0 when there are no used addresses for a // given seriesID/branch, so we do this to ensure there is an entry with // index==0. - if err := p.addUsedAddr(seriesID, branch, lastIdx); err != nil { + if err := p.addUsedAddr(ns, addrmgrNs, seriesID, branch, lastIdx); err != nil { return err } } lastIdx++ for lastIdx <= index { - if err := p.addUsedAddr(seriesID, branch, lastIdx); err != nil { + if err := p.addUsedAddr(ns, addrmgrNs, seriesID, branch, lastIdx); err != nil { return err } lastIdx++ @@ -744,7 +725,7 @@ func (p *Pool) EnsureUsedAddr(seriesID uint32, branch Branch, index Index) error // addUsedAddr creates a deposit script for the given seriesID/branch/index, // ensures it is imported into the address manager and finaly adds the script // hash to our used addresses DB. It must be called with the manager unlocked. -func (p *Pool) addUsedAddr(seriesID uint32, branch Branch, index Index) error { +func (p *Pool) addUsedAddr(ns, addrmgrNs walletdb.ReadWriteBucket, seriesID uint32, branch Branch, index Index) error { script, err := p.DepositScript(seriesID, branch, index) if err != nil { return err @@ -754,7 +735,7 @@ func (p *Pool) addUsedAddr(seriesID uint32, branch Branch, index Index) error { // to have it in the used addresses DB but not in the address manager. // TODO: Decide how far back we want the addr manager to rescan and set the // BlockStamp height according to that. - _, err = p.manager.ImportScript(script, &waddrmgr.BlockStamp{}) + _, err = p.manager.ImportScript(addrmgrNs, script, &waddrmgr.BlockStamp{}) if err != nil && err.(waddrmgr.ManagerError).ErrorCode != waddrmgr.ErrDuplicateAddress { return err } @@ -763,10 +744,7 @@ func (p *Pool) addUsedAddr(seriesID uint32, branch Branch, index Index) error { if err != nil { return newError(ErrCrypto, "failed to encrypt script hash", err) } - err = p.namespace.Update( - func(tx walletdb.Tx) error { - return putUsedAddrHash(tx, p.ID, seriesID, branch, index, encryptedHash) - }) + err = putUsedAddrHash(ns, p.ID, seriesID, branch, index, encryptedHash) if err != nil { return newError(ErrDatabase, "failed to store used addr script hash", err) } @@ -777,19 +755,11 @@ func (p *Pool) addUsedAddr(seriesID uint32, branch Branch, index Index) error { // getUsedAddr gets the script hash for the given series, branch and index from // the used addresses DB and uses that to look up the ManagedScriptAddress // from the address manager. It must be called with the manager unlocked. -func (p *Pool) getUsedAddr(seriesID uint32, branch Branch, index Index) ( +func (p *Pool) getUsedAddr(ns, addrmgrNs walletdb.ReadBucket, seriesID uint32, branch Branch, index Index) ( waddrmgr.ManagedScriptAddress, error) { mgr := p.manager - var encryptedHash []byte - err := p.namespace.View( - func(tx walletdb.Tx) error { - encryptedHash = getUsedAddrHash(tx, p.ID, seriesID, branch, index) - return nil - }) - if err != nil { - return nil, newError(ErrDatabase, "failed to lookup script hash for used addr", err) - } + encryptedHash := getUsedAddrHash(ns, p.ID, seriesID, branch, index) if encryptedHash == nil { return nil, nil } @@ -801,7 +771,7 @@ func (p *Pool) getUsedAddr(seriesID uint32, branch Branch, index Index) ( if err != nil { return nil, newError(ErrInvalidScriptHash, "failed to parse script hash", err) } - mAddr, err := mgr.Address(addr) + mAddr, err := mgr.Address(addrmgrNs, addr) if err != nil { return nil, err } @@ -811,15 +781,8 @@ func (p *Pool) getUsedAddr(seriesID uint32, branch Branch, index Index) ( // highestUsedIndexFor returns the highest index from this Pool's used addresses // with the given seriesID and branch. It returns 0 if there are no used // addresses with the given seriesID and branch. -func (p *Pool) highestUsedIndexFor(seriesID uint32, branch Branch) (Index, error) { - maxIdx := Index(0) - err := p.namespace.View( - func(tx walletdb.Tx) error { - var err error - maxIdx, err = getMaxUsedIdx(tx, p.ID, seriesID, branch) - return err - }) - return maxIdx, err +func (p *Pool) highestUsedIndexFor(ns walletdb.ReadBucket, seriesID uint32, branch Branch) (Index, error) { + return getMaxUsedIdx(ns, p.ID, seriesID, branch) } // String returns a string encoding of the underlying bitcoin payment address. diff --git a/votingpool/withdrawal.go b/votingpool/withdrawal.go index 13734c9..d1700ef 100644 --- a/votingpool/withdrawal.go +++ b/votingpool/withdrawal.go @@ -149,17 +149,17 @@ func (s outputStatus) String() string { return strings[s] } -func (tx *changeAwareTx) addSelfToStore(store *wtxmgr.Store) error { +func (tx *changeAwareTx) addSelfToStore(store *wtxmgr.Store, txmgrNs walletdb.ReadWriteBucket) error { rec, err := wtxmgr.NewTxRecordFromMsgTx(tx.MsgTx, time.Now()) if err != nil { return newError(ErrWithdrawalTxStorage, "error constructing TxRecord for storing", err) } - if err := store.InsertTx(rec, nil); err != nil { + if err := store.InsertTx(txmgrNs, rec, nil); err != nil { return newError(ErrWithdrawalTxStorage, "error adding tx to store", err) } if tx.changeIdx != -1 { - if err = store.AddCredit(rec, nil, uint32(tx.changeIdx), true); err != nil { + if err = store.AddCredit(txmgrNs, rec, nil, uint32(tx.changeIdx), true); err != nil { return newError(ErrWithdrawalTxStorage, "error adding tx credits to store", err) } } @@ -477,12 +477,12 @@ func newWithdrawal(roundID uint32, requests []OutputRequest, inputs []credit, // of those transaction's inputs. More details about the actual algorithm can be // found at http://opentransactions.org/wiki/index.php/Startwithdrawal // This method must be called with the address manager unlocked. -func (p *Pool) StartWithdrawal(roundID uint32, requests []OutputRequest, +func (p *Pool) StartWithdrawal(ns walletdb.ReadWriteBucket, addrmgrNs walletdb.ReadBucket, roundID uint32, requests []OutputRequest, startAddress WithdrawalAddress, lastSeriesID uint32, changeStart ChangeAddress, - txStore *wtxmgr.Store, chainHeight int32, dustThreshold btcutil.Amount) ( + txStore *wtxmgr.Store, txmgrNs walletdb.ReadBucket, chainHeight int32, dustThreshold btcutil.Amount) ( *WithdrawalStatus, error) { - status, err := getWithdrawalStatus(p, roundID, requests, startAddress, lastSeriesID, + status, err := getWithdrawalStatus(p, ns, addrmgrNs, roundID, requests, startAddress, lastSeriesID, changeStart, dustThreshold) if err != nil { return nil, err @@ -491,7 +491,7 @@ func (p *Pool) StartWithdrawal(roundID uint32, requests []OutputRequest, return status, nil } - eligible, err := p.getEligibleInputs(txStore, startAddress, lastSeriesID, dustThreshold, + eligible, err := p.getEligibleInputs(ns, addrmgrNs, txStore, txmgrNs, startAddress, lastSeriesID, dustThreshold, chainHeight, eligibleInputMinConfirmations) if err != nil { return nil, err @@ -511,10 +511,7 @@ func (p *Pool) StartWithdrawal(roundID uint32, requests []OutputRequest, if err != nil { return nil, err } - err = p.namespace.Update( - func(tx walletdb.Tx) error { - return putWithdrawal(tx, p.ID, roundID, serialized) - }) + err = putWithdrawal(ns, p.ID, roundID, serialized) if err != nil { return nil, err } @@ -819,23 +816,15 @@ func (wi *withdrawalInfo) match(requests []OutputRequest, startAddress Withdrawa // getWithdrawalStatus returns the existing WithdrawalStatus for the given // withdrawal parameters, if one exists. This function must be called with the // address manager unlocked. -func getWithdrawalStatus(p *Pool, roundID uint32, requests []OutputRequest, +func getWithdrawalStatus(p *Pool, ns, addrmgrNs walletdb.ReadBucket, roundID uint32, requests []OutputRequest, startAddress WithdrawalAddress, lastSeriesID uint32, changeStart ChangeAddress, dustThreshold btcutil.Amount) (*WithdrawalStatus, error) { - var serialized []byte - err := p.namespace.View( - func(tx walletdb.Tx) error { - serialized = getWithdrawal(tx, p.ID, roundID) - return nil - }) - if err != nil { - return nil, err - } + serialized := getWithdrawal(ns, p.ID, roundID) if bytes.Equal(serialized, []byte{}) { return nil, nil } - wInfo, err := deserializeWithdrawal(p, serialized) + wInfo, err := deserializeWithdrawal(p, ns, addrmgrNs, serialized) if err != nil { return nil, err } @@ -907,19 +896,19 @@ func getRawSigs(transactions []*withdrawalTx) (map[Ntxid]TxSigs, error) { // manager) the redeem script for each of them and constructing the signature // script using that and the given raw signatures. // This function must be called with the manager unlocked. -func SignTx(msgtx *wire.MsgTx, sigs TxSigs, mgr *waddrmgr.Manager, store *wtxmgr.Store) error { +func SignTx(msgtx *wire.MsgTx, sigs TxSigs, mgr *waddrmgr.Manager, addrmgrNs walletdb.ReadBucket, store *wtxmgr.Store, txmgrNs walletdb.ReadBucket) error { // We use time.Now() here as we're not going to store the new TxRecord // anywhere -- we just need it to pass to store.PreviousPkScripts(). rec, err := wtxmgr.NewTxRecordFromMsgTx(msgtx, time.Now()) if err != nil { return newError(ErrTxSigning, "failed to construct TxRecord for signing", err) } - pkScripts, err := store.PreviousPkScripts(rec, nil) + pkScripts, err := store.PreviousPkScripts(txmgrNs, rec, nil) if err != nil { return newError(ErrTxSigning, "failed to obtain pkScripts for signing", err) } for i, pkScript := range pkScripts { - if err = signMultiSigUTXO(mgr, msgtx, i, pkScript, sigs[i]); err != nil { + if err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, i, pkScript, sigs[i]); err != nil { return err } } @@ -928,8 +917,8 @@ func SignTx(msgtx *wire.MsgTx, sigs TxSigs, mgr *waddrmgr.Manager, store *wtxmgr // getRedeemScript returns the redeem script for the given P2SH address. It must // be called with the manager unlocked. -func getRedeemScript(mgr *waddrmgr.Manager, addr *btcutil.AddressScriptHash) ([]byte, error) { - address, err := mgr.Address(addr) +func getRedeemScript(mgr *waddrmgr.Manager, addrmgrNs walletdb.ReadBucket, addr *btcutil.AddressScriptHash) ([]byte, error) { + address, err := mgr.Address(addrmgrNs, addr) if err != nil { return nil, err } @@ -943,7 +932,7 @@ func getRedeemScript(mgr *waddrmgr.Manager, addr *btcutil.AddressScriptHash) ([] // The order of the signatures must match that of the public keys in the multi-sig // script as OP_CHECKMULTISIG expects that. // This function must be called with the manager unlocked. -func signMultiSigUTXO(mgr *waddrmgr.Manager, tx *wire.MsgTx, idx int, pkScript []byte, sigs []RawSig) error { +func signMultiSigUTXO(mgr *waddrmgr.Manager, addrmgrNs walletdb.ReadBucket, tx *wire.MsgTx, idx int, pkScript []byte, sigs []RawSig) error { class, addresses, _, err := txscript.ExtractPkScriptAddrs(pkScript, mgr.ChainParams()) if err != nil { return newError(ErrTxSigning, "unparseable pkScript", err) @@ -951,7 +940,7 @@ func signMultiSigUTXO(mgr *waddrmgr.Manager, tx *wire.MsgTx, idx int, pkScript [ if class != txscript.ScriptHashTy { return newError(ErrTxSigning, fmt.Sprintf("pkScript is not P2SH: %s", class), nil) } - redeemScript, err := getRedeemScript(mgr, addresses[0].(*btcutil.AddressScriptHash)) + redeemScript, err := getRedeemScript(mgr, addrmgrNs, addresses[0].(*btcutil.AddressScriptHash)) if err != nil { return newError(ErrTxSigning, "unable to retrieve redeem script", err) } @@ -1047,9 +1036,9 @@ func nextChangeAddress(a ChangeAddress) (ChangeAddress, error) { return *addr, err } -func storeTransactions(store *wtxmgr.Store, transactions []*changeAwareTx) error { +func storeTransactions(store *wtxmgr.Store, txmgrNs walletdb.ReadWriteBucket, transactions []*changeAwareTx) error { for _, tx := range transactions { - if err := tx.addSelfToStore(store); err != nil { + if err := tx.addSelfToStore(store, txmgrNs); err != nil { return err } }