Make votingpool package (sans tests) compile

This commit is contained in:
Josh Rickmar 2017-01-18 15:29:34 -05:00 committed by Olaoluwa Osuntokun
parent 4656a00705
commit f143d095d6
4 changed files with 113 additions and 157 deletions

View file

@ -117,10 +117,10 @@ func getUsedAddrBucketID(seriesID uint32, branch Branch) []byte {
// putUsedAddrHash adds an entry (key==index, value==encryptedHash) to the used // putUsedAddrHash adds an entry (key==index, value==encryptedHash) to the used
// addresses bucket of the given pool, series and branch. // 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 { 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)) bucket, err := usedAddrs.CreateBucketIfNotExists(getUsedAddrBucketID(seriesID, branch))
if err != nil { if err != nil {
return newError(ErrDatabase, "failed to store used address hash", err) 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 // getUsedAddrHash returns the addr hash with the given index from the used
// addresses bucket of the given pool, series and branch. // 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 { index Index) []byte {
usedAddrs := tx.RootBucket().Bucket(poolID).Bucket(usedAddrsBucketName) usedAddrs := ns.NestedReadBucket(poolID).NestedReadBucket(usedAddrsBucketName)
bucket := usedAddrs.Bucket(getUsedAddrBucketID(seriesID, branch)) bucket := usedAddrs.NestedReadBucket(getUsedAddrBucketID(seriesID, branch))
if bucket == nil { if bucket == nil {
return 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 // getMaxUsedIdx returns the highest used index from the used addresses bucket
// of the given pool, series and branch. // 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) maxIdx := Index(0)
usedAddrs := tx.RootBucket().Bucket(poolID).Bucket(usedAddrsBucketName) usedAddrs := ns.NestedReadBucket(poolID).NestedReadBucket(usedAddrsBucketName)
bucket := usedAddrs.Bucket(getUsedAddrBucketID(seriesID, branch)) bucket := usedAddrs.NestedReadBucket(getUsedAddrBucketID(seriesID, branch))
if bucket == nil { if bucket == nil {
return maxIdx, 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 // 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 // after the voting pool id and two other buckets inside it to store series and
// used addresses for that pool. // used addresses for that pool.
func putPool(tx walletdb.Tx, poolID []byte) error { func putPool(ns walletdb.ReadWriteBucket, poolID []byte) error {
poolBucket, err := tx.RootBucket().CreateBucket(poolID) poolBucket, err := ns.CreateBucket(poolID)
if err != nil { if err != nil {
return newError(ErrDatabase, fmt.Sprintf("cannot create pool %v", poolID), err) 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 // loadAllSeries returns a map of all the series stored inside a voting pool
// bucket, keyed by id. // bucket, keyed by id.
func loadAllSeries(tx walletdb.Tx, poolID []byte) (map[uint32]*dbSeriesRow, error) { func loadAllSeries(ns walletdb.ReadBucket, poolID []byte) (map[uint32]*dbSeriesRow, error) {
bucket := tx.RootBucket().Bucket(poolID).Bucket(seriesBucketName) bucket := ns.NestedReadBucket(poolID).NestedReadBucket(seriesBucketName)
allSeries := make(map[uint32]*dbSeriesRow) allSeries := make(map[uint32]*dbSeriesRow)
err := bucket.ForEach( err := bucket.ForEach(
func(k, v []byte) error { 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 // existsPool checks the existence of a bucket named after the given
// voting pool id. // voting pool id.
func existsPool(tx walletdb.Tx, poolID []byte) bool { func existsPool(ns walletdb.ReadBucket, poolID []byte) bool {
bucket := tx.RootBucket().Bucket(poolID) bucket := ns.NestedReadBucket(poolID)
return bucket != nil return bucket != nil
} }
// putSeries stores the given series inside a voting pool bucket named after // putSeries stores the given series inside a voting pool bucket named after
// poolID. The voting pool bucket does not need to be created beforehand. // 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{ row := &dbSeriesRow{
version: version, version: version,
active: active, active: active,
@ -234,19 +234,22 @@ func putSeries(tx walletdb.Tx, poolID []byte, version, ID uint32, active bool, r
pubKeysEncrypted: pubKeysEncrypted, pubKeysEncrypted: pubKeysEncrypted,
privKeysEncrypted: privKeysEncrypted, 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 // putSeriesRow stores the given series row inside a voting pool bucket named
// after poolID. The voting pool bucket does not need to be created // after poolID. The voting pool bucket does not need to be created
// beforehand. // beforehand.
func putSeriesRow(tx walletdb.Tx, poolID []byte, ID uint32, row *dbSeriesRow) error { func putSeriesRow(ns walletdb.ReadWriteBucket, poolID []byte, ID uint32, row *dbSeriesRow) error {
bucket, err := tx.RootBucket().CreateBucketIfNotExists(poolID) bucket, err := ns.CreateBucketIfNotExists(poolID)
if err != nil { if err != nil {
str := fmt.Sprintf("cannot create bucket %v", poolID) str := fmt.Sprintf("cannot create bucket %v", poolID)
return newError(ErrDatabase, str, err) return newError(ErrDatabase, str, err)
} }
bucket = bucket.Bucket(seriesBucketName) bucket, err = bucket.CreateBucketIfNotExists(seriesBucketName)
if err != nil {
return err
}
serialized, err := serializeSeriesRow(row) serialized, err := serializeSeriesRow(row)
if err != nil { if err != nil {
return err return err
@ -473,7 +476,7 @@ func serializeWithdrawal(requests []OutputRequest, startAddress WithdrawalAddres
// deserializeWithdrawal deserializes the given byte slice into a dbWithdrawalRow, // deserializeWithdrawal deserializes the given byte slice into a dbWithdrawalRow,
// converts it into an withdrawalInfo and returns it. This function must run // converts it into an withdrawalInfo and returns it. This function must run
// with the address manager unlocked. // 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 var row dbWithdrawalRow
if err := gob.NewDecoder(bytes.NewReader(serialized)).Decode(&row); err != nil { if err := gob.NewDecoder(bytes.NewReader(serialized)).Decode(&row); err != nil {
return nil, newError(ErrWithdrawalStorage, "cannot deserialize withdrawal information", return nil, newError(ErrWithdrawalStorage, "cannot deserialize withdrawal information",
@ -509,7 +512,7 @@ func deserializeWithdrawal(p *Pool, serialized []byte) (*withdrawalInfo, error)
requestsByOID[request.outBailmentID()] = request requestsByOID[request.outBailmentID()] = request
} }
startAddr := row.StartAddress 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 { if err != nil {
return nil, newError(ErrWithdrawalStorage, "cannot deserialize startAddress", err) return nil, newError(ErrWithdrawalStorage, "cannot deserialize startAddress", err)
} }
@ -564,13 +567,13 @@ func deserializeWithdrawal(p *Pool, serialized []byte) (*withdrawalInfo, error)
return wInfo, nil return wInfo, nil
} }
func putWithdrawal(tx walletdb.Tx, poolID []byte, roundID uint32, serialized []byte) error { func putWithdrawal(ns walletdb.ReadWriteBucket, poolID []byte, roundID uint32, serialized []byte) error {
bucket := tx.RootBucket().Bucket(poolID) bucket := ns.NestedReadWriteBucket(poolID)
return bucket.Put(uint32ToBytes(roundID), serialized) return bucket.Put(uint32ToBytes(roundID), serialized)
} }
func getWithdrawal(tx walletdb.Tx, poolID []byte, roundID uint32) []byte { func getWithdrawal(ns walletdb.ReadBucket, poolID []byte, roundID uint32) []byte {
bucket := tx.RootBucket().Bucket(poolID) bucket := ns.NestedReadBucket(poolID)
return bucket.Get(uint32ToBytes(roundID)) return bucket.Get(uint32ToBytes(roundID))
} }

View file

@ -21,10 +21,11 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/roasbeef/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/roasbeef/btcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/roasbeef/btcutil" "github.com/btcsuite/btcutil"
"github.com/roasbeef/btcwallet/wtxmgr" "github.com/btcsuite/btcwallet/walletdb"
"github.com/btcsuite/btcwallet/wtxmgr"
) )
const eligibleInputMinConfirmations = 100 const eligibleInputMinConfirmations = 100
@ -98,7 +99,7 @@ func (c byAddress) Less(i, j int) bool {
// getEligibleInputs returns eligible inputs with addresses between startAddress // getEligibleInputs returns eligible inputs with addresses between startAddress
// and the last used address of lastSeriesID. They're reverse ordered based on // and the last used address of lastSeriesID. They're reverse ordered based on
// their address. // 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, lastSeriesID uint32, dustThreshold btcutil.Amount, chainHeight int32,
minConf int) ([]credit, error) { 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) str := fmt.Sprintf("lastSeriesID (%d) does not exist", lastSeriesID)
return nil, newError(ErrSeriesNotExists, str, nil) return nil, newError(ErrSeriesNotExists, str, nil)
} }
unspents, err := store.UnspentOutputs() unspents, err := store.UnspentOutputs(txmgrNs)
if err != nil { if err != nil {
return nil, newError(ErrInputSelection, "failed to get unspent outputs", err) 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...) 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 { if err != nil {
return nil, newError(ErrInputSelection, "failed to get next withdrawal address", err) return nil, newError(ErrInputSelection, "failed to get next withdrawal address", err)
} else if nAddr == nil { } 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 // nextAddr returns the next WithdrawalAddress according to the input selection
// rules: http://opentransactions.org/wiki/index.php/Input_Selection_Algorithm_(voting_pools) // rules: http://opentransactions.org/wiki/index.php/Input_Selection_Algorithm_(voting_pools)
// It returns nil if the new address' seriesID is >= stopSeriesID. // 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) { *WithdrawalAddress, error) {
series := p.Series(seriesID) series := p.Series(seriesID)
if series == nil { if series == nil {
@ -152,7 +153,7 @@ func nextAddr(p *Pool, seriesID uint32, branch Branch, index Index, stopSeriesID
} }
branch++ branch++
if int(branch) > len(series.publicKeys) { if int(branch) > len(series.publicKeys) {
highestIdx, err := p.highestUsedSeriesIndex(seriesID) highestIdx, err := p.highestUsedSeriesIndex(ns, seriesID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -171,14 +172,14 @@ func nextAddr(p *Pool, seriesID uint32, branch Branch, index Index, stopSeriesID
return nil, nil 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 { if err != nil && err.(Error).ErrorCode == ErrWithdrawFromUnusedAddr {
// The used indices will vary between branches so sometimes we'll try to // 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 // get a WithdrawalAddress that hasn't been used before, and in such
// cases we just need to move on to the next one. // 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 "+ log.Debugf("nextAddr(): skipping addr (series #%d, branch #%d, index #%d) as it hasn't "+
"been used before", seriesID, branch, index) "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 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 // 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 // used addresses for the given seriesID. It returns 0 if there are no used
// addresses with the given seriesID. // 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) maxIdx := Index(0)
series := p.Series(seriesID) series := p.Series(seriesID)
if series == nil { if series == nil {
@ -194,7 +195,7 @@ func (p *Pool) highestUsedSeriesIndex(seriesID uint32) (Index, error) {
newError(ErrSeriesNotExists, fmt.Sprintf("unknown seriesID: %d", seriesID), nil) newError(ErrSeriesNotExists, fmt.Sprintf("unknown seriesID: %d", seriesID), nil)
} }
for i := range series.publicKeys { for i := range series.publicKeys {
idx, err := p.highestUsedIndexFor(seriesID, Branch(i)) idx, err := p.highestUsedIndexFor(ns, seriesID, Branch(i))
if err != nil { if err != nil {
return Index(0), err return Index(0), err
} }

View file

@ -48,7 +48,6 @@ type Pool struct {
ID []byte ID []byte
seriesLookup map[uint32]*SeriesData seriesLookup map[uint32]*SeriesData
manager *waddrmgr.Manager manager *waddrmgr.Manager
namespace walletdb.Namespace
} }
// PoolAddress represents a voting pool P2SH address, generated by // 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 // Create creates a new entry in the database with the given ID
// and returns the Pool representing it. // and returns the Pool representing it.
func Create(namespace walletdb.Namespace, m *waddrmgr.Manager, poolID []byte) (*Pool, error) { func Create(ns walletdb.ReadWriteBucket, m *waddrmgr.Manager, poolID []byte) (*Pool, error) {
err := namespace.Update( err := putPool(ns, poolID)
func(tx walletdb.Tx) error {
return putPool(tx, poolID)
})
if err != nil { if err != nil {
str := fmt.Sprintf("unable to add voting pool %v to db", poolID) str := fmt.Sprintf("unable to add voting pool %v to db", poolID)
return nil, newError(ErrPoolAlreadyExists, str, err) 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 // Load fetches the entry in the database with the given ID and returns the Pool
// representing it. // representing it.
func Load(namespace walletdb.Namespace, m *waddrmgr.Manager, poolID []byte) (*Pool, error) { func Load(ns walletdb.ReadBucket, m *waddrmgr.Manager, poolID []byte) (*Pool, error) {
err := namespace.View( if !existsPool(ns, poolID) {
func(tx walletdb.Tx) error {
if exists := existsPool(tx, poolID); !exists {
str := fmt.Sprintf("unable to find voting pool %v in db", poolID) str := fmt.Sprintf("unable to find voting pool %v in db", poolID)
return newError(ErrPoolNotExists, str, nil) return nil, newError(ErrPoolNotExists, str, nil)
} }
return nil p := newPool(m, poolID)
}) if err := p.LoadAllSeries(ns); err != nil {
if err != nil {
return nil, err
}
p := newPool(namespace, m, poolID)
if err = p.LoadAllSeries(); err != nil {
return nil, err return nil, err
} }
return p, nil return p, nil
} }
// newPool creates a new Pool instance. // 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{ return &Pool{
ID: poolID, ID: poolID,
seriesLookup: make(map[uint32]*SeriesData), seriesLookup: make(map[uint32]*SeriesData),
manager: m, manager: m,
namespace: namespace,
} }
} }
// LoadAndGetDepositScript generates and returns a deposit script for the given seriesID, // LoadAndGetDepositScript generates and returns a deposit script for the given seriesID,
// branch and index of the Pool identified by poolID. // 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) pid := []byte(poolID)
p, err := Load(namespace, m, pid) p, err := Load(ns, m, pid)
if err != nil { if err != nil {
return nil, err 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 // 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 // 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. // 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 { poolID string, seriesID, reqSigs uint32, rawPubKeys []string) error {
pid := []byte(poolID) pid := []byte(poolID)
p, err := Load(namespace, m, pid) p, err := Load(ns, m, pid)
if err != nil { if err != nil {
vpErr := err.(Error) vpErr := err.(Error)
if vpErr.ErrorCode == ErrPoolNotExists { if vpErr.ErrorCode == ErrPoolNotExists {
p, err = Create(namespace, m, pid) p, err = Create(ns, m, pid)
if err != nil { if err != nil {
return err return err
} }
@ -159,31 +147,31 @@ func LoadAndCreateSeries(namespace walletdb.Namespace, m *waddrmgr.Manager, vers
return err 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, // LoadAndReplaceSeries loads the voting pool with the given ID and calls ReplaceSeries,
// passing the given series ID, public keys and reqSigs to it. // 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 { poolID string, seriesID, reqSigs uint32, rawPubKeys []string) error {
pid := []byte(poolID) pid := []byte(poolID)
p, err := Load(namespace, m, pid) p, err := Load(ns, m, pid)
if err != nil { if err != nil {
return err 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, // LoadAndEmpowerSeries loads the voting pool with the given ID and calls EmpowerSeries,
// passing the given series ID and private key to it. // 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 { poolID string, seriesID uint32, rawPrivKey string) error {
pid := []byte(poolID) pid := []byte(poolID)
pool, err := Load(namespace, m, pid) pool, err := Load(ns, m, pid)
if err != nil { if err != nil {
return err 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 // 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. // first encrypting the public/private extended keys.
// //
// This method must be called with the Pool's manager unlocked. // 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 var err error
encryptedPubKeys := make([][]byte, len(data.publicKeys)) encryptedPubKeys := make([][]byte, len(data.publicKeys))
for i, pubKey := range 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 { err = putSeries(ns, p.ID, data.version, seriesID, data.active,
return putSeries(tx, p.ID, data.version, seriesID, data.active,
data.reqSigs, encryptedPubKeys, encryptedPrivKeys) data.reqSigs, encryptedPubKeys, encryptedPrivKeys)
})
if err != nil { if err != nil {
str := fmt.Sprintf("cannot put series #%d into db", seriesID) str := fmt.Sprintf("cannot put series #%d into db", seriesID)
return newError(ErrSeriesSerialization, str, err) return newError(ErrSeriesSerialization, str, err)
@ -286,7 +272,7 @@ func convertAndValidatePubKeys(rawPubKeys []string) ([]*hdkeychain.ExtendedKey,
// inRawPubKeys. // inRawPubKeys.
// //
// This method must be called with the Pool's manager unlocked. // 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 { if len(inRawPubKeys) < minSeriesPubKeys {
str := fmt.Sprintf("need at least %d public keys to create a series", minSeriesPubKeys) str := fmt.Sprintf("need at least %d public keys to create a series", minSeriesPubKeys)
return newError(ErrTooFewPublicKeys, str, nil) 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)), privateKeys: make([]*hdkeychain.ExtendedKey, len(keys)),
} }
err = p.saveSeriesToDisk(seriesID, data) err = p.saveSeriesToDisk(ns, seriesID, data)
if err != nil { if err != nil {
return err return err
} }
@ -326,7 +312,7 @@ func (p *Pool) putSeries(version, seriesID, reqSigs uint32, inRawPubKeys []strin
// - seriesID must be greater than or equal 1; // - seriesID must be greater than or equal 1;
// - rawPubKeys has to contain three or more public keys; // - rawPubKeys has to contain three or more public keys;
// - reqSigs has to be less or equal than the number of public keys in rawPubKeys. // - 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 { if seriesID == 0 {
return newError(ErrSeriesIDInvalid, "series ID cannot be 0", nil) 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. // 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) series := p.Series(seriesID)
if series == nil { if series == nil {
str := fmt.Sprintf("series #%d does not exist, cannot activate it", seriesID) str := fmt.Sprintf("series #%d does not exist, cannot activate it", seriesID)
return newError(ErrSeriesNotExists, str, nil) return newError(ErrSeriesNotExists, str, nil)
} }
series.active = true series.active = true
err := p.saveSeriesToDisk(seriesID, series) err := p.saveSeriesToDisk(ns, seriesID, series)
if err != nil { if err != nil {
return err return err
} }
@ -367,7 +353,7 @@ func (p *Pool) ActivateSeries(seriesID uint32) error {
// //
// - rawPubKeys has to contain three or more public keys // - rawPubKeys has to contain three or more public keys
// - reqSigs has to be less or equal than the number of public keys in rawPubKeys. // - 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) series := p.Series(seriesID)
if series == nil { if series == nil {
str := fmt.Sprintf("series #%d does not exist, cannot replace it", seriesID) 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 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 // 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. // This method must be called with the Pool's manager unlocked.
// FIXME: We should be able to get rid of this (and loadAllSeries/seriesLookup) // FIXME: We should be able to get rid of this (and loadAllSeries/seriesLookup)
// by making Series() load the series data directly from the DB. // by making Series() load the series data directly from the DB.
func (p *Pool) LoadAllSeries() error { func (p *Pool) LoadAllSeries(ns walletdb.ReadBucket) error {
var series map[uint32]*dbSeriesRow series, err := loadAllSeries(ns, p.ID)
err := p.namespace.View(func(tx walletdb.Tx) error {
var err error
series, err = loadAllSeries(tx, p.ID)
return err
})
if err != nil { if err != nil {
return err 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 // 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. // it'd be too expensive to re-generate the redeem script for all of them.
// This method must be called with the manager unlocked. // 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) { *WithdrawalAddress, error) {
// TODO: Ensure the given series is hot. // 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 { if err != nil {
return nil, err 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. // private extended key and must match one of the series' extended public keys.
// //
// This method must be called with the Pool's manager unlocked. // 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 // make sure this series exists
series := p.Series(seriesID) series := p.Series(seriesID)
if series == nil { if series == nil {
@ -708,7 +689,7 @@ func (p *Pool) EmpowerSeries(seriesID uint32, rawPrivKey string) error {
return newError(ErrKeysPrivatePublicMismatch, str, nil) return newError(ErrKeysPrivatePublicMismatch, str, nil)
} }
if err = p.saveSeriesToDisk(seriesID, series); err != nil { if err = p.saveSeriesToDisk(ns, seriesID, series); err != nil {
return err 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 // 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 // seriesID, branch and all indices up to the given one. It must be called with
// the manager unlocked. // the manager unlocked.
func (p *Pool) EnsureUsedAddr(seriesID uint32, branch Branch, index Index) error { func (p *Pool) EnsureUsedAddr(ns, addrmgrNs walletdb.ReadWriteBucket, seriesID uint32, branch Branch, index Index) error {
lastIdx, err := p.highestUsedIndexFor(seriesID, branch) lastIdx, err := p.highestUsedIndexFor(ns, seriesID, branch)
if err != nil { if err != nil {
return err 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 // 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 // given seriesID/branch, so we do this to ensure there is an entry with
// index==0. // index==0.
if err := p.addUsedAddr(seriesID, branch, lastIdx); err != nil { if err := p.addUsedAddr(ns, addrmgrNs, seriesID, branch, lastIdx); err != nil {
return err return err
} }
} }
lastIdx++ lastIdx++
for lastIdx <= index { 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 return err
} }
lastIdx++ 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, // addUsedAddr creates a deposit script for the given seriesID/branch/index,
// ensures it is imported into the address manager and finaly adds the script // 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. // 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) script, err := p.DepositScript(seriesID, branch, index)
if err != nil { if err != nil {
return err 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. // 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 // TODO: Decide how far back we want the addr manager to rescan and set the
// BlockStamp height according to that. // 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 { if err != nil && err.(waddrmgr.ManagerError).ErrorCode != waddrmgr.ErrDuplicateAddress {
return err return err
} }
@ -763,10 +744,7 @@ func (p *Pool) addUsedAddr(seriesID uint32, branch Branch, index Index) error {
if err != nil { if err != nil {
return newError(ErrCrypto, "failed to encrypt script hash", err) return newError(ErrCrypto, "failed to encrypt script hash", err)
} }
err = p.namespace.Update( err = putUsedAddrHash(ns, p.ID, seriesID, branch, index, encryptedHash)
func(tx walletdb.Tx) error {
return putUsedAddrHash(tx, p.ID, seriesID, branch, index, encryptedHash)
})
if err != nil { if err != nil {
return newError(ErrDatabase, "failed to store used addr script hash", err) 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 // 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 // the used addresses DB and uses that to look up the ManagedScriptAddress
// from the address manager. It must be called with the manager unlocked. // 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) { waddrmgr.ManagedScriptAddress, error) {
mgr := p.manager mgr := p.manager
var encryptedHash []byte encryptedHash := getUsedAddrHash(ns, p.ID, seriesID, branch, index)
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)
}
if encryptedHash == nil { if encryptedHash == nil {
return nil, nil return nil, nil
} }
@ -801,7 +771,7 @@ func (p *Pool) getUsedAddr(seriesID uint32, branch Branch, index Index) (
if err != nil { if err != nil {
return nil, newError(ErrInvalidScriptHash, "failed to parse script hash", err) return nil, newError(ErrInvalidScriptHash, "failed to parse script hash", err)
} }
mAddr, err := mgr.Address(addr) mAddr, err := mgr.Address(addrmgrNs, addr)
if err != nil { if err != nil {
return nil, err 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 // 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 // with the given seriesID and branch. It returns 0 if there are no used
// addresses with the given seriesID and branch. // addresses with the given seriesID and branch.
func (p *Pool) highestUsedIndexFor(seriesID uint32, branch Branch) (Index, error) { func (p *Pool) highestUsedIndexFor(ns walletdb.ReadBucket, seriesID uint32, branch Branch) (Index, error) {
maxIdx := Index(0) return getMaxUsedIdx(ns, p.ID, seriesID, branch)
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
} }
// String returns a string encoding of the underlying bitcoin payment address. // String returns a string encoding of the underlying bitcoin payment address.

View file

@ -149,17 +149,17 @@ func (s outputStatus) String() string {
return strings[s] 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()) rec, err := wtxmgr.NewTxRecordFromMsgTx(tx.MsgTx, time.Now())
if err != nil { if err != nil {
return newError(ErrWithdrawalTxStorage, "error constructing TxRecord for storing", err) 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) return newError(ErrWithdrawalTxStorage, "error adding tx to store", err)
} }
if tx.changeIdx != -1 { 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) 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 // of those transaction's inputs. More details about the actual algorithm can be
// found at http://opentransactions.org/wiki/index.php/Startwithdrawal // found at http://opentransactions.org/wiki/index.php/Startwithdrawal
// This method must be called with the address manager unlocked. // 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, 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) { *WithdrawalStatus, error) {
status, err := getWithdrawalStatus(p, roundID, requests, startAddress, lastSeriesID, status, err := getWithdrawalStatus(p, ns, addrmgrNs, roundID, requests, startAddress, lastSeriesID,
changeStart, dustThreshold) changeStart, dustThreshold)
if err != nil { if err != nil {
return nil, err return nil, err
@ -491,7 +491,7 @@ func (p *Pool) StartWithdrawal(roundID uint32, requests []OutputRequest,
return status, nil return status, nil
} }
eligible, err := p.getEligibleInputs(txStore, startAddress, lastSeriesID, dustThreshold, eligible, err := p.getEligibleInputs(ns, addrmgrNs, txStore, txmgrNs, startAddress, lastSeriesID, dustThreshold,
chainHeight, eligibleInputMinConfirmations) chainHeight, eligibleInputMinConfirmations)
if err != nil { if err != nil {
return nil, err return nil, err
@ -511,10 +511,7 @@ func (p *Pool) StartWithdrawal(roundID uint32, requests []OutputRequest,
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = p.namespace.Update( err = putWithdrawal(ns, p.ID, roundID, serialized)
func(tx walletdb.Tx) error {
return putWithdrawal(tx, p.ID, roundID, serialized)
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -819,23 +816,15 @@ func (wi *withdrawalInfo) match(requests []OutputRequest, startAddress Withdrawa
// getWithdrawalStatus returns the existing WithdrawalStatus for the given // getWithdrawalStatus returns the existing WithdrawalStatus for the given
// withdrawal parameters, if one exists. This function must be called with the // withdrawal parameters, if one exists. This function must be called with the
// address manager unlocked. // 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, startAddress WithdrawalAddress, lastSeriesID uint32, changeStart ChangeAddress,
dustThreshold btcutil.Amount) (*WithdrawalStatus, error) { dustThreshold btcutil.Amount) (*WithdrawalStatus, error) {
var serialized []byte serialized := getWithdrawal(ns, p.ID, roundID)
err := p.namespace.View(
func(tx walletdb.Tx) error {
serialized = getWithdrawal(tx, p.ID, roundID)
return nil
})
if err != nil {
return nil, err
}
if bytes.Equal(serialized, []byte{}) { if bytes.Equal(serialized, []byte{}) {
return nil, nil return nil, nil
} }
wInfo, err := deserializeWithdrawal(p, serialized) wInfo, err := deserializeWithdrawal(p, ns, addrmgrNs, serialized)
if err != nil { if err != nil {
return nil, err 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 // manager) the redeem script for each of them and constructing the signature
// script using that and the given raw signatures. // script using that and the given raw signatures.
// This function must be called with the manager unlocked. // 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 // 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(). // anywhere -- we just need it to pass to store.PreviousPkScripts().
rec, err := wtxmgr.NewTxRecordFromMsgTx(msgtx, time.Now()) rec, err := wtxmgr.NewTxRecordFromMsgTx(msgtx, time.Now())
if err != nil { if err != nil {
return newError(ErrTxSigning, "failed to construct TxRecord for signing", err) 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 { if err != nil {
return newError(ErrTxSigning, "failed to obtain pkScripts for signing", err) return newError(ErrTxSigning, "failed to obtain pkScripts for signing", err)
} }
for i, pkScript := range pkScripts { 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 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 // getRedeemScript returns the redeem script for the given P2SH address. It must
// be called with the manager unlocked. // be called with the manager unlocked.
func getRedeemScript(mgr *waddrmgr.Manager, addr *btcutil.AddressScriptHash) ([]byte, error) { func getRedeemScript(mgr *waddrmgr.Manager, addrmgrNs walletdb.ReadBucket, addr *btcutil.AddressScriptHash) ([]byte, error) {
address, err := mgr.Address(addr) address, err := mgr.Address(addrmgrNs, addr)
if err != nil { if err != nil {
return nil, err 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 // The order of the signatures must match that of the public keys in the multi-sig
// script as OP_CHECKMULTISIG expects that. // script as OP_CHECKMULTISIG expects that.
// This function must be called with the manager unlocked. // 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()) class, addresses, _, err := txscript.ExtractPkScriptAddrs(pkScript, mgr.ChainParams())
if err != nil { if err != nil {
return newError(ErrTxSigning, "unparseable pkScript", err) 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 { if class != txscript.ScriptHashTy {
return newError(ErrTxSigning, fmt.Sprintf("pkScript is not P2SH: %s", class), nil) 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 { if err != nil {
return newError(ErrTxSigning, "unable to retrieve redeem script", err) return newError(ErrTxSigning, "unable to retrieve redeem script", err)
} }
@ -1047,9 +1036,9 @@ func nextChangeAddress(a ChangeAddress) (ChangeAddress, error) {
return *addr, err 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 { for _, tx := range transactions {
if err := tx.addSelfToStore(store); err != nil { if err := tx.addSelfToStore(store, txmgrNs); err != nil {
return err return err
} }
} }