本文整理汇总了Golang中github.com/decred/dcrwallet/walletdb.Update函数的典型用法代码示例。如果您正苦于以下问题:Golang Update函数的具体用法?Golang Update怎么用?Golang Update使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了Update函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Golang代码示例。
示例1: handleChainVotingNotifications
func (w *Wallet) handleChainVotingNotifications() {
chainClient, err := w.requireChainClient()
if err != nil {
log.Error(err)
w.wg.Done()
return
}
for n := range chainClient.NotificationsVoting() {
var err error
strErrType := ""
switch n := n.(type) {
case chain.WinningTickets:
err = walletdb.Update(w.db, func(dbtx walletdb.ReadWriteTx) error {
return w.handleWinningTickets(dbtx, n.BlockHash, n.BlockHeight, n.Tickets)
})
strErrType = "WinningTickets"
case chain.MissedTickets:
err = walletdb.Update(w.db, func(dbtx walletdb.ReadWriteTx) error {
return w.handleMissedTickets(dbtx, n.BlockHash, n.BlockHeight, n.Tickets)
})
strErrType = "MissedTickets"
default:
err = fmt.Errorf("voting handler received unknown ntfn type")
}
if err != nil {
log.Errorf("Cannot handle chain server voting "+
"notification %v: %v", strErrType, err)
}
}
w.wg.Done()
}
示例2: handleConsensusRPCNotifications
func (w *Wallet) handleConsensusRPCNotifications(chainClient *chain.RPCClient) {
for n := range chainClient.Notifications() {
var notificationName string
var err error
switch n := n.(type) {
case chain.ClientConnected:
log.Infof("The client has successfully connected to dcrd and " +
"is now handling websocket notifications")
case chain.BlockConnected:
notificationName = "blockconnected"
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
return w.onBlockConnected(tx, n.BlockHeader, n.Transactions)
})
case chain.Reorganization:
notificationName = "reorganizing"
err = w.handleReorganizing(n.OldHash, n.NewHash, n.OldHeight, n.NewHeight)
case chain.RelevantTxAccepted:
notificationName = "relevanttxaccepted"
err = walletdb.Update(w.db, func(dbtx walletdb.ReadWriteTx) error {
return w.processTransaction(dbtx, n.Transaction, nil, nil)
})
}
if err != nil {
log.Errorf("Failed to process consensus server notification "+
"(name: `%s`, detail: `%v`)", notificationName, err)
}
}
}
示例3: rescanProgressHandler
// rescanProgressHandler handles notifications for partially and fully completed
// rescans by marking each rescanned address as partially or fully synced.
func (w *Wallet) rescanProgressHandler() {
quit := w.quitChan()
out:
for {
// These can't be processed out of order since both chans are
// unbuffured and are sent from same context (the batch
// handler).
select {
case msg := <-w.rescanProgress:
n := msg.Notification
log.Infof("Rescanned through block %v (height %d)",
n.Hash, n.Height)
bs := waddrmgr.BlockStamp{
Hash: *n.Hash,
Height: n.Height,
}
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return w.Manager.SetSyncedTo(ns, &bs)
})
if err != nil {
log.Errorf("Failed to update address manager "+
"sync state for hash %v (height %d): %v",
n.Hash, n.Height, err)
}
case msg := <-w.rescanFinished:
n := msg.Notification
addrs := msg.Addresses
noun := pickNoun(len(addrs), "address", "addresses")
log.Infof("Finished rescan for %d %s (synced to block "+
"%s, height %d)", len(addrs), noun, n.Hash,
n.Height)
bs := waddrmgr.BlockStamp{
Height: n.Height,
Hash: *n.Hash,
}
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
return w.Manager.SetSyncedTo(ns, &bs)
})
if err != nil {
log.Errorf("Failed to update address manager "+
"sync state for hash %v (height %d): %v",
n.Hash, n.Height, err)
continue
}
w.SetChainSynced(true)
go w.resendUnminedTxs()
case <-quit:
break out
}
}
w.wg.Done()
}
示例4: handleChainNotifications
// handleChainNotifications is the major chain notification handler that
// receives websocket notifications about the blockchain.
func (w *Wallet) handleChainNotifications() {
chainClient, err := w.requireChainClient()
if err != nil {
log.Errorf("handleChainNotifications called without RPC client")
w.wg.Done()
return
}
// At the moment there is no recourse if the rescan fails for
// some reason, however, the wallet will not be marked synced
// and many methods will error early since the wallet is known
// to be out of date.
err = w.syncWithChain()
if err != nil && !w.ShuttingDown() {
log.Warnf("Unable to synchronize wallet to chain: %v", err)
}
for n := range chainClient.Notifications() {
var err error
strErrType := ""
switch n := n.(type) {
case chain.ClientConnected:
log.Infof("The client has successfully connected to dcrd and " +
"is now handling websocket notifications")
case chain.BlockConnected:
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
return w.connectBlock(tx, wtxmgr.BlockMeta(n))
})
strErrType = "BlockConnected"
case chain.BlockDisconnected:
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
return w.disconnectBlock(tx, wtxmgr.BlockMeta(n))
})
strErrType = "BlockDisconnected"
case chain.Reorganization:
w.handleReorganizing(n.OldHash, n.OldHeight, n.NewHash, n.NewHeight)
case chain.RelevantTx:
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
return w.addRelevantTx(tx, n.TxRecord, n.Block)
})
strErrType = "RelevantTx"
// The following are handled by the wallet's rescan
// goroutines, so just pass them there.
case *chain.RescanProgress, *chain.RescanFinished:
w.rescanNotifications <- n
}
if err != nil {
log.Errorf("Cannot handle chain server "+
"notification %v: %v", strErrType, err)
}
}
w.wg.Done()
}
示例5: ImportP2SHRedeemScript
// ImportP2SHRedeemScript adds a P2SH redeem script to the wallet.
func (w *Wallet) ImportP2SHRedeemScript(script []byte) (*dcrutil.AddressScriptHash, error) {
var p2shAddr *dcrutil.AddressScriptHash
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
txmgrNs := tx.ReadWriteBucket(wtxmgrNamespaceKey)
err := w.TxStore.InsertTxScript(txmgrNs, script)
if err != nil {
return err
}
addrInfo, err := w.Manager.ImportScript(addrmgrNs, script)
if err != nil {
// Don't care if it's already there, but still have to
// set the p2shAddr since the address manager didn't
// return anything useful.
if waddrmgr.IsError(err, waddrmgr.ErrDuplicateAddress) {
// This function will never error as it always
// hashes the script to the correct length.
p2shAddr, _ = dcrutil.NewAddressScriptHash(script,
w.chainParams)
return nil
}
return err
}
p2shAddr = addrInfo.Address().(*dcrutil.AddressScriptHash)
return nil
})
return p2shAddr, err
}
示例6: NewAddress
// NewAddress checks the address pools and then attempts to return a new
// address for the account and branch requested.
func (w *Wallet) NewAddress(account uint32, branch uint32) (dcrutil.Address, error) {
var address dcrutil.Address
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
waddrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
err := w.CheckAddressPoolsInitialized(account)
if err != nil {
return err
}
var addrPool *addressPool
switch branch {
case waddrmgr.ExternalBranch:
addrPool = w.getAddressPools(account).external
case waddrmgr.InternalBranch:
addrPool = w.getAddressPools(account).internal
default:
return fmt.Errorf("new address failed; unknown branch number %v",
branch)
}
address, err = addrPool.GetNewAddress(waddrmgrNs)
return err
})
return address, err
}
示例7: SetVoteBitsForTickets
// SetVoteBitsForTickets sets vote bits for many given tickets. These vote bits
// override the wallet's default vote bits.
func (w *Wallet) SetVoteBitsForTickets(tickets []chainhash.Hash,
voteBitsSlice []stake.VoteBits) error {
if len(tickets) != len(voteBitsSlice) {
return fmt.Errorf("number of tickets (%v) and number of vote bits "+
"(%v) not equal", len(tickets), len(voteBitsSlice))
}
for i := range voteBitsSlice {
// Sanity check for the extended voteBits length.
if len(voteBitsSlice[i].ExtendedBits) >
stake.MaxSingleBytePushLength-2 {
return fmt.Errorf("bad extended votebits length (got %v, max %v)",
len(voteBitsSlice[i].ExtendedBits),
stake.MaxSingleBytePushLength-2)
}
}
return walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
stakemgrNs := tx.ReadWriteBucket(wstakemgrNamespaceKey)
var err error
for i := range tickets {
err = w.StakeMgr.UpdateSStxVoteBits(stakemgrNs, &tickets[i],
voteBitsSlice[i])
if err != nil {
return err
}
}
return nil
})
}
示例8: handleChainNotifications
// handleChainNotifications is the major chain notification handler that
// receives websocket notifications about the blockchain.
func (w *Wallet) handleChainNotifications() {
chainClient, err := w.requireChainClient()
if err != nil {
log.Errorf("handleChainNotifications called without RPC client")
w.wg.Done()
return
}
// At the moment there is no recourse if the rescan fails for
// some reason, however, the wallet will not be marked synced
// and many methods will error early since the wallet is known
// to be out of date.
err = w.syncWithChain()
if err != nil && !w.ShuttingDown() {
log.Warnf("Unable to synchronize wallet to chain: %v", err)
}
for n := range chainClient.Notifications() {
var notificationName string
var err error
switch n := n.(type) {
case chain.ClientConnected:
log.Infof("The client has successfully connected to dcrd and " +
"is now handling websocket notifications")
case chain.BlockConnected:
notificationName = "blockconnected"
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
return w.onBlockConnected(tx, n.BlockHeader, n.Transactions)
})
case chain.Reorganization:
notificationName = "reorganizing"
err = w.handleReorganizing(n.OldHash, n.NewHash, n.OldHeight, n.NewHeight)
case chain.RelevantTxAccepted:
notificationName = "relevanttxaccepted"
err = walletdb.Update(w.db, func(dbtx walletdb.ReadWriteTx) error {
return w.processTransaction(dbtx, n.Transaction, nil, nil)
})
}
if err != nil {
log.Errorf("Failed to process consensus server notification "+
"(name: `%s`, detail: `%v`)", notificationName, err)
}
}
w.wg.Done()
}
示例9: SyncAddressPoolIndex
// SyncAddressPoolIndex synchronizes an account's branch to the given address
// by iteratively calling getNewAddress on the respective address pool.
func (w *Wallet) SyncAddressPoolIndex(account uint32, branch uint32, index uint32) error {
// Sanity checks.
err := w.CheckAddressPoolsInitialized(account)
if err != nil {
return err
}
return walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
waddrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
defer func() {
errNotify := w.notifyAccountAddrIdxs(waddrmgrNs, account)
if errNotify != nil {
log.Errorf("Failed to push account update notification "+
"for account %v", account)
}
}()
var addrPool *addressPool
switch branch {
case waddrmgr.ExternalBranch:
addrPool = w.getAddressPools(account).external
addrPool.mutex.Lock()
defer addrPool.mutex.Unlock()
case waddrmgr.InternalBranch:
addrPool = w.getAddressPools(account).internal
addrPool.mutex.Lock()
defer addrPool.mutex.Unlock()
default:
return fmt.Errorf("unknown branch number %v", branch)
}
if index < addrPool.index {
return fmt.Errorf("the passed index, %v, is before the "+
"currently synced to address index %v", index,
addrPool.index)
}
if index == addrPool.index {
return nil
}
// Synchronize our address pool by calling getNewAddress
// iteratively until the next to use index is synced to
// where we need it.
toFetch := index - addrPool.index
for i := uint32(0); i < toFetch; i++ {
_, err := addrPool.getNewAddress(waddrmgrNs)
if err != nil {
addrPool.BatchRollback()
return err
}
}
addrPool.BatchFinish(waddrmgrNs)
return nil
})
}
示例10: mainInt
func mainInt() int {
fmt.Println("Database path:", opts.DbPath)
_, err := os.Stat(opts.DbPath)
if os.IsNotExist(err) {
fmt.Println("Database file does not exist")
return 1
}
for !opts.Force {
fmt.Print("Drop all dcrwallet transaction history? [y/N] ")
scanner := bufio.NewScanner(bufio.NewReader(os.Stdin))
if !scanner.Scan() {
// Exit on EOF.
return 0
}
err := scanner.Err()
if err != nil {
fmt.Println()
fmt.Println(err)
return 1
}
resp := scanner.Text()
if yes(resp) {
break
}
if no(resp) || resp == "" {
return 0
}
fmt.Println("Enter yes or no.")
}
db, err := walletdb.Open("bdb", opts.DbPath)
if err != nil {
fmt.Println("Failed to open database:", err)
return 1
}
defer db.Close()
fmt.Println("Dropping wtxmgr namespace")
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
return tx.DeleteTopLevelBucket(wtxmgrNamespace)
})
if err != nil && err != walletdb.ErrBucketNotFound {
fmt.Println("Failed to drop namespace:", err)
return 1
}
return 0
}
示例11: SetVoteBitsForTicket
// SetVoteBitsForTicket sets the per-ticket vote bits. These vote bits override
// the wallet's default vote bits.
func (w *Wallet) SetVoteBitsForTicket(ticket *chainhash.Hash,
voteBits stake.VoteBits) error {
// Sanity check for the extended voteBits length.
if len(voteBits.ExtendedBits) > stake.MaxSingleBytePushLength-2 {
return fmt.Errorf("bad extended votebits length (got %v, max %v)",
len(voteBits.ExtendedBits), stake.MaxSingleBytePushLength-2)
}
return walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
stakemgrNs := tx.ReadWriteBucket(wstakemgrNamespaceKey)
return w.StakeMgr.UpdateSStxVoteBits(stakemgrNs, ticket,
voteBits)
})
}
示例12: AddTicket
// AddTicket adds a ticket transaction to the wallet.
func (w *Wallet) AddTicket(ticket *dcrutil.Tx) error {
return walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
stakemgrNs := tx.ReadWriteBucket(wstakemgrNamespaceKey)
// Insert the ticket to be tracked and voted.
err := w.StakeMgr.InsertSStx(stakemgrNs, ticket, w.VoteBits)
if err != nil {
return err
}
if w.stakePoolEnabled {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
// Pluck the ticketaddress to indentify the stakepool user.
pkVersion := ticket.MsgTx().TxOut[0].Version
pkScript := ticket.MsgTx().TxOut[0].PkScript
_, addrs, _, err := txscript.ExtractPkScriptAddrs(pkVersion,
pkScript, w.ChainParams())
if err != nil {
return err
}
ticketHash := ticket.MsgTx().TxSha()
chainClient, err := w.requireChainClient()
if err != nil {
return err
}
rawTx, err := chainClient.GetRawTransactionVerbose(&ticketHash)
if err != nil {
return err
}
// Update the pool ticket stake. This will include removing it from the
// invalid slice and adding a ImmatureOrLive ticket to the valid ones.
err = w.updateStakePoolInvalidTicket(stakemgrNs, addrmgrNs, addrs[0], &ticketHash, rawTx.BlockHeight)
if err != nil {
return err
}
}
return nil
})
}
示例13: DiscoverActiveAddresses
// DiscoverActiveAddresses accesses the consensus RPC server to discover all the
// addresses that have been used by an HD keychain stemming from this wallet. If
// discoverAccts is true, used accounts will be discovered as well. This
// feature requires the wallet to be unlocked in order to derive hardened
// account extended pubkeys.
//
// A transaction filter (re)load and rescan should be performed after discovery.
//
// BUG(jrick): This function reassigns address pools, and if called multiple
// times it would not be unlikely to see address reuse due to losing the address
// pool's derivation index. I am punting on this for now. In the future,
// address pools should be removed and all derivation should be done solely by
// waddrmgr. Use with caution.
func (w *Wallet) DiscoverActiveAddresses(chainClient *chain.RPCClient, discoverAccts bool) error {
log.Infof("Beginning a rescan of active addresses using the daemon. " +
"This may take a while.")
// Search external branch then internal branch for a used address. We need
// to set the address function to use based on whether or not this is the
// initial sync. The function AddressDerivedFromCointype is able to see
// addresses that exists in accounts that have not yet been created, while
// AddressDerivedFromDbAcct can not.
derive := w.Manager.AddressDerivedFromDbAcct
if discoverAccts {
derive = w.Manager.AddressDerivedFromCointype
}
ctx := &discoveryContext{chainClient: chainClient, deriveAddr: derive}
// Start by rescanning the accounts and determining what the
// current account index is. This scan should only ever be
// performed if we're restoring our wallet from seed.
var lastAcct uint32
if w.initiallyUnlocked {
var err error
lastAcct, err = w.scanAccountIndex(ctx, 0, waddrmgr.MaxAccountNum)
if err != nil {
return err
}
}
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
lastAcctMgr, err := w.Manager.LastAccount(addrmgrNs)
if err != nil {
return err
}
// The address manager is not synced (wallet has been restored
// from seed?). In this case, spawn the accounts in the address
// manager first. The accounts are named by their respective
// index number, as strings.
if lastAcctMgr < lastAcct {
for i := lastAcctMgr + 1; i <= lastAcct; i++ {
_, err := w.Manager.NewAccount(
addrmgrNs, strconv.Itoa(int(i)))
if err != nil {
return err
}
}
}
// The account manager has a greater index than the rescan.
// It is likely that the end user created a new account but
// did not use it yet. Rescan it anyway so that the address
// pool is created.
if lastAcctMgr > lastAcct {
lastAcct = lastAcctMgr
}
return nil
})
if err != nil {
return err
}
log.Infof("The last used account was %v. Beginning a rescan for "+
"all active addresses in known accounts.", lastAcct)
// Rescan addresses for the both the internal and external
// branches of the account. Insert a new address pool for
// the respective account and initialize it.
for acct := uint32(0); acct <= lastAcct; acct++ {
var extIdx, intIdx uint32
// Do this for both external (0) and internal (1) branches.
for branch := uint32(0); branch < 2; branch++ {
idx, lastAddr, err := w.scanAddressIndex(ctx, 0,
waddrmgr.MaxAddressesPerAccount, acct, branch)
if err != nil {
return err
}
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
// If the account is unused, buffer the initial address pool
// by syncing the address manager upstream.
unusedAcct := (lastAddr == nil)
if unusedAcct {
_, err := w.Manager.SyncAccountToAddrIndex(
//.........这里部分代码省略.........
示例14: TestCursorDeletions
func TestCursorDeletions(t *testing.T) {
t.Skip("Cursor deletion APIs have been removed until bolt issue #620 is resolved")
db, _, teardown, err := setup()
defer teardown()
if err != nil {
t.Fatal(err)
}
err = walletdb.Update(db, func(dbtx walletdb.ReadWriteTx) error {
txHash := decodeHash("2b29213f06354455c235021e541604607ed738b1bc6217f2fe3ae5bffbfe1218")
ks := [][]byte{
canonicalOutPoint(txHash, 0),
canonicalOutPoint(txHash, 1),
}
vs := [][]byte{
valueUnminedCredit(1e8, false, 0, false, scriptTypeP2PKH, 0, 0, 0),
valueUnminedCredit(2e8, true, 0, false, scriptTypeP2PKH, 0, 0, 0),
}
ns := dbtx.ReadWriteBucket(wtxmgrNamespaceKey)
for i := range ks {
err = putRawUnminedCredit(ns, ks[i], vs[i])
if err != nil {
return err
}
}
iterations := 0
// Test the iterator iterates over each.
it := makeUnminedCreditIterator(ns, txHash)
for it.next() {
iterations++
}
if iterations != 2 {
t.Errorf("Expected to iterate over two k/v pairs, but iterated %v time(s)", iterations)
}
iterations = 0
// Test the iterator can be used to delete each.
it = makeUnminedCreditIterator(ns, txHash)
for it.next() {
//err = it.delete()
if err != nil {
return err
}
iterations++
}
if iterations != 2 {
t.Errorf("Expected to iterate over and delete two k/v pairs, but iterated %v time(s)", iterations)
}
it = makeUnminedCreditIterator(ns, txHash)
for it.next() {
t.Error("Did not delete every k/v pair from bucket using iterator")
break
}
return nil
})
if err != nil {
t.Error(err)
}
}
示例15: TestStakeInvalidationOfTip
func TestStakeInvalidationOfTip(t *testing.T) {
db, s, teardown, err := setup()
defer teardown()
if err != nil {
t.Fatal(err)
}
g := makeBlockGenerator()
block1Header := g.generate(dcrutil.BlockValid)
block2Header := g.generate(dcrutil.BlockValid)
block3Header := g.generate(0)
block1Tx := wire.MsgTx{
TxOut: []*wire.TxOut{{Value: 2e8}},
}
block2Tx := wire.MsgTx{
TxIn: []*wire.TxIn{
{PreviousOutPoint: wire.OutPoint{Hash: block1Tx.TxSha(), Index: 0, Tree: 0}},
},
TxOut: []*wire.TxOut{{Value: 1e8}},
}
block1TxRec, err := NewTxRecordFromMsgTx(&block1Tx, time.Time{})
if err != nil {
t.Fatal(err)
}
block2TxRec, err := NewTxRecordFromMsgTx(&block2Tx, time.Time{})
if err != nil {
t.Fatal(err)
}
const balanceFlag = BFBalanceSpendable
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(wtxmgrNamespaceKey)
addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
err := s.InsertMemPoolTx(ns, block1TxRec)
if err != nil {
return err
}
err = s.AddCredit(ns, block1TxRec, nil, 0, false, 0)
if err != nil {
return err
}
err = s.InsertMemPoolTx(ns, block2TxRec)
if err != nil {
return err
}
err = s.AddCredit(ns, block2TxRec, nil, 0, false, 0)
if err != nil {
return err
}
bal, err := s.Balance(ns, addrmgrNs, 0, balanceFlag, false, 0)
if err != nil {
return err
}
if bal != 1e8 {
t.Errorf("Wrong balance before mining either transaction: %v", bal)
}
headerData := makeHeaderDataSlice(block1Header, block2Header)
err = s.InsertMainChainHeaders(ns, addrmgrNs, headerData)
if err != nil {
return err
}
err = s.InsertMinedTx(ns, addrmgrNs, block1TxRec, &headerData[0].BlockHash)
if err != nil {
return err
}
err = s.InsertMinedTx(ns, addrmgrNs, block2TxRec, &headerData[1].BlockHash)
if err != nil {
return err
}
// At this point there should only be one credit for the tx in block 2.
bal, err = s.Balance(ns, addrmgrNs, 1, balanceFlag, false, 0)
if err != nil {
return err
}
if bal != dcrutil.Amount(block2Tx.TxOut[0].Value) {
t.Errorf("Wrong balance: expected %v got %v", dcrutil.Amount(block2Tx.TxOut[0].Value), bal)
}
credits, err := s.UnspentOutputs(ns)
if err != nil {
return err
}
if len(credits) != 1 {
t.Errorf("Expected only 1 credit, got %v", len(credits))
return nil
}
if credits[0].Hash != block2Tx.TxSha() {
t.Errorf("Credit hash does match tx from block 2")
return nil
}
if credits[0].Amount != dcrutil.Amount(block2Tx.TxOut[0].Value) {
t.Errorf("Credit value does not match tx output 0 from block 2")
return nil
}
//.........这里部分代码省略.........