// 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) { maxIdx := Index(0) usedAddrs := tx.RootBucket().Bucket(poolID).Bucket(usedAddrsBucketName) bucket := usedAddrs.Bucket(getUsedAddrBucketID(seriesID, branch)) if bucket == nil { return maxIdx, nil } // FIXME: This is far from optimal and should be optimized either by storing // a separate key in the DB with the highest used idx for every // series/branch or perhaps by doing a large gap linear forward search + // binary backwards search (e.g. check for 1000000, 2000000, .... until it // doesn't exist, and then use a binary search to find the max using the // discovered bounds). err := bucket.ForEach( func(k, v []byte) error { idx := Index(bytesToUint32(k)) if idx > maxIdx { maxIdx = idx } return nil }) if err != nil { return Index(0), newError(ErrDatabase, "failed to get highest idx of used addresses", err) } return maxIdx, nil }
// 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, index Index) []byte { usedAddrs := tx.RootBucket().Bucket(poolID).Bucket(usedAddrsBucketName) bucket := usedAddrs.Bucket(getUsedAddrBucketID(seriesID, branch)) if bucket == nil { return nil } return bucket.Get(uint32ToBytes(uint32(index))) }
// 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, index Index, encryptedHash []byte) error { usedAddrs := tx.RootBucket().Bucket(poolID).Bucket(usedAddrsBucketName) bucket, err := usedAddrs.CreateBucketIfNotExists(getUsedAddrBucketID(seriesID, branch)) if err != nil { return newError(ErrDatabase, "failed to store used address hash", err) } return bucket.Put(uint32ToBytes(uint32(index)), encryptedHash) }
// 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) if err != nil { str := fmt.Sprintf("cannot create bucket %v", poolID) return newError(ErrDatabase, str, err) } bucket = bucket.Bucket(seriesBucketName) serialized, err := serializeSeriesRow(row) if err != nil { return err } err = bucket.Put(uint32ToBytes(ID), serialized) if err != nil { str := fmt.Sprintf("cannot put series %v into bucket %v", serialized, poolID) return newError(ErrDatabase, str, err) } return nil }
// 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) allSeries := make(map[uint32]*dbSeriesRow) err := bucket.ForEach( func(k, v []byte) error { seriesID := bytesToUint32(k) series, err := deserializeSeriesRow(v) if err != nil { return err } allSeries[seriesID] = series return nil }) if err != nil { return nil, err } return allSeries, nil }
// 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) if err != nil { return newError(ErrDatabase, fmt.Sprintf("cannot create pool %v", poolID), err) } _, err = poolBucket.CreateBucket(seriesBucketName) if err != nil { return newError(ErrDatabase, fmt.Sprintf("cannot create series bucket for pool %v", poolID), err) } _, err = poolBucket.CreateBucket(usedAddrsBucketName) if err != nil { return newError(ErrDatabase, fmt.Sprintf("cannot create used addrs bucket for pool %v", poolID), err) } _, err = poolBucket.CreateBucket(withdrawalsBucketName) if err != nil { return newError( ErrDatabase, fmt.Sprintf("cannot create withdrawals bucket for pool %v", poolID), err) } return nil }
func getWithdrawal(tx walletdb.Tx, poolID []byte, roundID uint32) []byte { bucket := tx.RootBucket().Bucket(poolID) return bucket.Get(uint32ToBytes(roundID)) }
func putWithdrawal(tx walletdb.Tx, poolID []byte, roundID uint32, serialized []byte) error { bucket := tx.RootBucket().Bucket(poolID) return bucket.Put(uint32ToBytes(roundID), serialized) }
// 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) return bucket != nil }