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
// 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))
}

View file

@ -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
}

View file

@ -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.

View file

@ -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
}
}