From 7cfa843832877db7d305d01c1cfb58df3471891a Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 23 Jun 2015 15:43:39 -0400 Subject: [PATCH 01/27] Support getmempoolinfo. --- btcjson/chainsvrresults.go | 7 +++++++ docs/json_rpc_api.md | 43 +++++++++++++++++++++++++------------- rpcserver.go | 18 ++++++++++++++++ rpcserverhelp.go | 8 +++++++ 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index 168d0034..c0efd7cd 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -122,6 +122,13 @@ type GetBlockTemplateResult struct { RejectReasion string `json:"reject-reason,omitempty"` } +// GetMempoolInfoResult models the data returned from the getmempoolinfo +// command. +type GetMempoolInfoResult struct { + Size int64 `json:"size"` + Bytes int64 `json:"bytes"` +} + // GetNetworkInfoResult models the data returned from the getnetworkinfo // command. type GetNetworkInfoResult struct { diff --git a/docs/json_rpc_api.md b/docs/json_rpc_api.md index 7d3620f4..7c1192ef 100644 --- a/docs/json_rpc_api.md +++ b/docs/json_rpc_api.md @@ -162,21 +162,22 @@ the method name for further details such as parameter and return information. |12|[getgenerate](#getgenerate)|N|Return if the server is set to generate coins (mine) or not.| |13|[gethashespersec](#gethashespersec)|N|Returns a recent hashes per second performance measurement while generating coins (mining).| |14|[getinfo](#getinfo)|Y|Returns a JSON object containing various state info.| -|15|[getmininginfo](#getmininginfo)|N|Returns a JSON object containing mining-related information.| -|16|[getnettotals](#getnettotals)|Y|Returns a JSON object containing network traffic statistics.| -|17|[getnetworkhashps](#getnetworkhashps)|Y|Returns the estimated network hashes per second for the block heights provided by the parameters.| -|18|[getpeerinfo](#getpeerinfo)|N|Returns information about each connected network peer as an array of json objects.| -|19|[getrawmempool](#getrawmempool)|Y|Returns an array of hashes for all of the transactions currently in the memory pool.| -|20|[getrawtransaction](#getrawtransaction)|Y|Returns information about a transaction given its hash.| -|21|[getwork](#getwork)|N|Returns formatted hash data to work on or checks and submits solved data.
NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.| -|22|[help](#help)|Y|Returns a list of all commands or help for a specified command.| -|23|[ping](#ping)|N|Queues a ping to be sent to each connected peer.| -|24|[sendrawtransaction](#sendrawtransaction)|Y|Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.
btcd does not yet implement the `allowhighfees` parameter, so it has no effect| -|25|[setgenerate](#setgenerate) |N|Set the server to generate coins (mine) or not.
NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.| -|26|[stop](#stop)|N|Shutdown btcd.| -|27|[submitblock](#submitblock)|Y|Attempts to submit a new serialized, hex-encoded block to the network.| -|28|[validateaddress](#validateaddress)|Y|Verifies the given address is valid. NOTE: Since btcd does not have a wallet integrated, btcd will only return whether the address is valid or not.| -|29|[verifychain](#verifychain)|N|Verifies the block chain database.| +|15|[getmempoolinfo](#getmempoolinfo)|N|Returns a JSON object containing mempool-related information.| +|16|[getmininginfo](#getmininginfo)|N|Returns a JSON object containing mining-related information.| +|17|[getnettotals](#getnettotals)|Y|Returns a JSON object containing network traffic statistics.| +|18|[getnetworkhashps](#getnetworkhashps)|Y|Returns the estimated network hashes per second for the block heights provided by the parameters.| +|19|[getpeerinfo](#getpeerinfo)|N|Returns information about each connected network peer as an array of json objects.| +|20|[getrawmempool](#getrawmempool)|Y|Returns an array of hashes for all of the transactions currently in the memory pool.| +|21|[getrawtransaction](#getrawtransaction)|Y|Returns information about a transaction given its hash.| +|22|[getwork](#getwork)|N|Returns formatted hash data to work on or checks and submits solved data.
NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.| +|23|[help](#help)|Y|Returns a list of all commands or help for a specified command.| +|24|[ping](#ping)|N|Queues a ping to be sent to each connected peer.| +|25|[sendrawtransaction](#sendrawtransaction)|Y|Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.
btcd does not yet implement the `allowhighfees` parameter, so it has no effect| +|26|[setgenerate](#setgenerate) |N|Set the server to generate coins (mine) or not.
NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.| +|27|[stop](#stop)|N|Shutdown btcd.| +|28|[submitblock](#submitblock)|Y|Attempts to submit a new serialized, hex-encoded block to the network.| +|29|[validateaddress](#validateaddress)|Y|Verifies the given address is valid. NOTE: Since btcd does not have a wallet integrated, btcd will only return whether the address is valid or not.| +|30|[verifychain](#verifychain)|N|Verifies the block chain database.| **5.2 Method Details**
@@ -352,6 +353,18 @@ the method name for further details such as parameter and return information. |Example Return|`{`
  `"version": 70000`
  `"protocolversion": 70001, `
  `"blocks": 298963,`
  `"timeoffset": 0,`
  `"connections": 17,`
  `"proxy": "",`
  `"difficulty": 8000872135.97,`
  `"testnet": false,`
  `"relayfee": 0.00001,`
`}`| [Return to Overview](#MethodOverview)
+*** +
+ +| | | +|---|---| +|Method|getmempoolinfo| +|Parameters|None| +|Description|Returns a JSON object containing mempool-related information.| +|Returns|`{ (json object)`
  `"bytes": n, (numeric) size in bytes of the mempool`
  `"size": n, (numeric) number of transactions in the mempool`
`}`| +Example Return|`{`
  `"bytes": 310768,`
  `"size": 157,`
`}`| +[Return to Overview](#MethodOverview)
+ ***
diff --git a/rpcserver.go b/rpcserver.go index 797eadef..58fcf657 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -146,6 +146,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "getgenerate": handleGetGenerate, "gethashespersec": handleGetHashesPerSec, "getinfo": handleGetInfo, + "getmempoolinfo": handleGetMempoolInfo, "getmininginfo": handleGetMiningInfo, "getnettotals": handleGetNetTotals, "getnetworkhashps": handleGetNetworkHashPS, @@ -1938,6 +1939,23 @@ func handleGetInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (in return ret, nil } +// handleGetMempoolInfo implements the getmempoolinfo command. +func handleGetMempoolInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + txD := s.server.txMemPool.TxDescs() + + var numBytes int64 + for _, desc := range txD { + numBytes += int64(desc.Tx.MsgTx().SerializeSize()) + } + + ret := &btcjson.GetMempoolInfoResult{ + Size: int64(len(txD)), + Bytes: numBytes, + } + + return ret, nil +} + // handleGetMiningInfo implements the getmininginfo command. We only return the // fields that are not related to wallet functionality. func handleGetMiningInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { diff --git a/rpcserverhelp.go b/rpcserverhelp.go index f14250e0..4f44b8e9 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -288,6 +288,13 @@ var helpDescsEnUS = map[string]string{ // GetInfoCmd help. "getinfo--synopsis": "Returns a JSON object containing various state info.", + // GetMempoolInfoCmd help. + "getmempoolinfo--synopsis": "Returns memory pool information", + + // GetMempoolInfoResult help. + "getmempoolinforesult-bytes": "Size in bytes of the mempool", + "getmempoolinforesult-size": "Number of transactions in the mempool", + // GetMiningInfoResult help. "getmininginforesult-blocks": "Height of the latest best block", "getmininginforesult-currentblocksize": "Size of the latest best block", @@ -540,6 +547,7 @@ var rpcResultTypes = map[string][]interface{}{ "getgenerate": []interface{}{(*bool)(nil)}, "gethashespersec": []interface{}{(*float64)(nil)}, "getinfo": []interface{}{(*btcjson.InfoChainResult)(nil)}, + "getmempoolinfo": []interface{}{(*btcjson.GetMempoolInfoResult)(nil)}, "getmininginfo": []interface{}{(*btcjson.GetMiningInfoResult)(nil)}, "getnettotals": []interface{}{(*btcjson.GetNetTotalsResult)(nil)}, "getnetworkhashps": []interface{}{(*int64)(nil)}, From 527f585463b8654d20dbcdc3bc322a9ab169fe2e Mon Sep 17 00:00:00 2001 From: David Hill Date: Fri, 26 Jun 2015 10:11:51 -0400 Subject: [PATCH 02/27] txscript: Move lockTimeThreshold to txscript Move lockTimeThreshold to txscript and export it. This is a consensus value which txscript will need in an upcoming diff. --- blockchain/validate.go | 11 ++--------- log.go | 11 ++--------- txscript/consensus.go | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 txscript/consensus.go diff --git a/blockchain/validate.go b/blockchain/validate.go index 8d2dd721..0fc9a949 100644 --- a/blockchain/validate.go +++ b/blockchain/validate.go @@ -23,13 +23,6 @@ const ( // allowed for a block. It is a fraction of the max block payload size. MaxSigOpsPerBlock = wire.MaxBlockPayload / 50 - // lockTimeThreshold is the number below which a lock time is - // interpreted to be a block number. Since an average of one block - // is generated per 10 minutes, this allows blocks for about 9,512 - // years. However, if the field is interpreted as a timestamp, given - // the lock time is a uint32, the max is sometime around 2106. - lockTimeThreshold uint32 = 5e8 // Tue Nov 5 00:53:20 1985 UTC - // MaxTimeOffsetSeconds is the maximum number of seconds a block time // is allowed to be ahead of the current time. This is currently 2 // hours. @@ -146,10 +139,10 @@ func IsFinalizedTransaction(tx *btcutil.Tx, blockHeight int64, blockTime time.Ti // The lock time field of a transaction is either a block height at // which the transaction is finalized or a timestamp depending on if the - // value is before the lockTimeThreshold. When it is under the + // value is before the txscript.LockTimeThreshold. When it is under the // threshold it is a block height. blockTimeOrHeight := int64(0) - if lockTime < lockTimeThreshold { + if lockTime < txscript.LockTimeThreshold { blockTimeOrHeight = blockHeight } else { blockTimeOrHeight = blockTime.Unix() diff --git a/log.go b/log.go index f73d73f6..058fcbf9 100644 --- a/log.go +++ b/log.go @@ -21,13 +21,6 @@ import ( ) const ( - // lockTimeThreshold is the number below which a lock time is - // interpreted to be a block number. Since an average of one block - // is generated per 10 minutes, this allows blocks for about 9,512 - // years. However, if the field is interpreted as a timestamp, given - // the lock time is a uint32, the max is sometime around 2106. - lockTimeThreshold uint32 = 5e8 // Tue Nov 5 00:53:20 1985 UTC - // maxRejectReasonLen is the maximum length of a sanitized reject reason // that will be logged. maxRejectReasonLen = 250 @@ -214,9 +207,9 @@ func directionString(inbound bool) string { func formatLockTime(lockTime uint32) string { // The lock time field of a transaction is either a block height at // which the transaction is finalized or a timestamp depending on if the - // value is before the lockTimeThreshold. When it is under the + // value is before the txscript.LockTimeThreshold. When it is under the // threshold it is a block height. - if lockTime < lockTimeThreshold { + if lockTime < txscript.LockTimeThreshold { return fmt.Sprintf("height %d", lockTime) } diff --git a/txscript/consensus.go b/txscript/consensus.go new file mode 100644 index 00000000..1aec5028 --- /dev/null +++ b/txscript/consensus.go @@ -0,0 +1,14 @@ +// Copyright (c) 2015 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package txscript + +const ( + // LockTimeThreshold is the number below which a lock time is + // interpreted to be a block number. Since an average of one block + // is generated per 10 minutes, this allows blocks for about 9,512 + // years. However, if the field is interpreted as a timestamp, given + // the lock time is a uint32, the max is sometime around 2106. + LockTimeThreshold uint32 = 5e8 // Tue Nov 5 00:53:20 1985 UTC +) From bb8333a73927145535cb58143913fd1f97fb6e07 Mon Sep 17 00:00:00 2001 From: David Hill Date: Sat, 27 Jun 2015 11:04:10 -0400 Subject: [PATCH 03/27] Use NewMsgInvSizeHint when we know the size. When trickling inv's to peers, allocate for the number of inv's in the queue instead of the default 1000. This should save on memory. --- peer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peer.go b/peer.go index 16047daa..eed6c552 100644 --- a/peer.go +++ b/peer.go @@ -1670,7 +1670,7 @@ out: // Create and send as many inv messages as needed to // drain the inventory send queue. - invMsg := wire.NewMsgInv() + invMsg := wire.NewMsgInvSizeHint(uint(invSendQueue.Len())) for e := invSendQueue.Front(); e != nil; e = invSendQueue.Front() { iv := invSendQueue.Remove(e).(*wire.InvVect) @@ -1685,7 +1685,7 @@ out: waiting = queuePacket( outMsg{msg: invMsg}, pendingMsgs, waiting) - invMsg = wire.NewMsgInv() + invMsg = wire.NewMsgInvSizeHint(uint(invSendQueue.Len())) } // Add the inventory that is being relayed to From 17da2ba7fa691c666d70948217ffcd5b6ac148f8 Mon Sep 17 00:00:00 2001 From: David Hill Date: Fri, 26 Jun 2015 13:48:10 -0400 Subject: [PATCH 04/27] Move IsFinalizedTransaction to txscript. This change moves IsFinalizedTransaction to txscript and also changes the first argument to take a wire.MsgTx instead of btcutil.Tx. This is needed for an upcoming diff in which txscript will require IsFinalizedTransaction and we do not want to import the btcd/blockchain. --- blockchain/validate.go | 37 +------------------------------------ mempool.go | 2 +- mining.go | 2 +- txscript/consensus.go | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/blockchain/validate.go b/blockchain/validate.go index 0fc9a949..0ee18deb 100644 --- a/blockchain/validate.go +++ b/blockchain/validate.go @@ -127,41 +127,6 @@ func IsCoinBase(tx *btcutil.Tx) bool { return IsCoinBaseTx(tx.MsgTx()) } -// IsFinalizedTransaction determines whether or not a transaction is finalized. -func IsFinalizedTransaction(tx *btcutil.Tx, blockHeight int64, blockTime time.Time) bool { - msgTx := tx.MsgTx() - - // Lock time of zero means the transaction is finalized. - lockTime := msgTx.LockTime - if lockTime == 0 { - return true - } - - // The lock time field of a transaction is either a block height at - // which the transaction is finalized or a timestamp depending on if the - // value is before the txscript.LockTimeThreshold. When it is under the - // threshold it is a block height. - blockTimeOrHeight := int64(0) - if lockTime < txscript.LockTimeThreshold { - blockTimeOrHeight = blockHeight - } else { - blockTimeOrHeight = blockTime.Unix() - } - if int64(lockTime) < blockTimeOrHeight { - return true - } - - // At this point, the transaction's lock time hasn't occured yet, but - // the transaction might still be finalized if the sequence number - // for all transaction inputs is maxed out. - for _, txIn := range msgTx.TxIn { - if txIn.Sequence != math.MaxUint32 { - return false - } - } - return true -} - // isBIP0030Node returns whether or not the passed node represents one of the // two blocks that violate the BIP0030 rule which prevents transactions from // overwriting old ones. @@ -707,7 +672,7 @@ func (b *BlockChain) checkBlockContext(block *btcutil.Block, prevNode *blockNode // Ensure all transactions in the block are finalized. for _, tx := range block.Transactions() { - if !IsFinalizedTransaction(tx, blockHeight, + if !txscript.IsFinalizedTransaction(tx.MsgTx(), blockHeight, header.Timestamp) { str := fmt.Sprintf("block contains unfinalized "+ diff --git a/mempool.go b/mempool.go index ebcaf5f7..ada0db59 100644 --- a/mempool.go +++ b/mempool.go @@ -237,7 +237,7 @@ func (mp *txMemPool) checkTransactionStandard(tx *btcutil.Tx, height int64) erro // The transaction must be finalized to be standard and therefore // considered for inclusion in a block. adjustedTime := mp.server.timeSource.AdjustedTime() - if !blockchain.IsFinalizedTransaction(tx, height, adjustedTime) { + if !txscript.IsFinalizedTransaction(tx.MsgTx(), height, adjustedTime) { return txRuleError(wire.RejectNonstandard, "transaction is not finalized") } diff --git a/mining.go b/mining.go index 4af91138..0b739111 100644 --- a/mining.go +++ b/mining.go @@ -446,7 +446,7 @@ mempoolLoop: minrLog.Tracef("Skipping coinbase tx %s", tx.Sha()) continue } - if !blockchain.IsFinalizedTransaction(tx, nextBlockHeight, + if !txscript.IsFinalizedTransaction(tx.MsgTx(), nextBlockHeight, timeSource.AdjustedTime()) { minrLog.Tracef("Skipping non-finalized tx %s", tx.Sha()) diff --git a/txscript/consensus.go b/txscript/consensus.go index 1aec5028..de73389c 100644 --- a/txscript/consensus.go +++ b/txscript/consensus.go @@ -4,6 +4,13 @@ package txscript +import ( + "math" + "time" + + "github.com/btcsuite/btcd/wire" +) + const ( // LockTimeThreshold is the number below which a lock time is // interpreted to be a block number. Since an average of one block @@ -12,3 +19,36 @@ const ( // the lock time is a uint32, the max is sometime around 2106. LockTimeThreshold uint32 = 5e8 // Tue Nov 5 00:53:20 1985 UTC ) + +// IsFinalizedTransaction determines whether or not a transaction is finalized. +func IsFinalizedTransaction(msgTx *wire.MsgTx, blockHeight int64, blockTime time.Time) bool { + // Lock time of zero means the transaction is finalized. + lockTime := msgTx.LockTime + if lockTime == 0 { + return true + } + + // The lock time field of a transaction is either a block height at + // which the transaction is finalized or a timestamp depending on if the + // value is before the LockTimeThreshold. When it is under the + // threshold it is a block height. + blockTimeOrHeight := int64(0) + if lockTime < LockTimeThreshold { + blockTimeOrHeight = blockHeight + } else { + blockTimeOrHeight = blockTime.Unix() + } + if int64(lockTime) < blockTimeOrHeight { + return true + } + + // At this point, the transaction's lock time hasn't occured yet, but + // the transaction might still be finalized if the sequence number + // for all transaction inputs is maxed out. + for _, txIn := range msgTx.TxIn { + if txIn.Sequence != math.MaxUint32 { + return false + } + } + return true +} From 9ffd96bf5161b1f2033ba7732286947178967a22 Mon Sep 17 00:00:00 2001 From: David Hill Date: Mon, 29 Jun 2015 11:12:35 -0400 Subject: [PATCH 05/27] Revert "Move IsFinalizedTransaction to txscript." This reverts commit 17da2ba7fa691c666d70948217ffcd5b6ac148f8. This was done prematurely. This will be revisited when a code restructure is more urgent. --- blockchain/validate.go | 37 ++++++++++++++++++++++++++++++++++++- mempool.go | 2 +- mining.go | 2 +- txscript/consensus.go | 40 ---------------------------------------- 4 files changed, 38 insertions(+), 43 deletions(-) diff --git a/blockchain/validate.go b/blockchain/validate.go index 0ee18deb..0fc9a949 100644 --- a/blockchain/validate.go +++ b/blockchain/validate.go @@ -127,6 +127,41 @@ func IsCoinBase(tx *btcutil.Tx) bool { return IsCoinBaseTx(tx.MsgTx()) } +// IsFinalizedTransaction determines whether or not a transaction is finalized. +func IsFinalizedTransaction(tx *btcutil.Tx, blockHeight int64, blockTime time.Time) bool { + msgTx := tx.MsgTx() + + // Lock time of zero means the transaction is finalized. + lockTime := msgTx.LockTime + if lockTime == 0 { + return true + } + + // The lock time field of a transaction is either a block height at + // which the transaction is finalized or a timestamp depending on if the + // value is before the txscript.LockTimeThreshold. When it is under the + // threshold it is a block height. + blockTimeOrHeight := int64(0) + if lockTime < txscript.LockTimeThreshold { + blockTimeOrHeight = blockHeight + } else { + blockTimeOrHeight = blockTime.Unix() + } + if int64(lockTime) < blockTimeOrHeight { + return true + } + + // At this point, the transaction's lock time hasn't occured yet, but + // the transaction might still be finalized if the sequence number + // for all transaction inputs is maxed out. + for _, txIn := range msgTx.TxIn { + if txIn.Sequence != math.MaxUint32 { + return false + } + } + return true +} + // isBIP0030Node returns whether or not the passed node represents one of the // two blocks that violate the BIP0030 rule which prevents transactions from // overwriting old ones. @@ -672,7 +707,7 @@ func (b *BlockChain) checkBlockContext(block *btcutil.Block, prevNode *blockNode // Ensure all transactions in the block are finalized. for _, tx := range block.Transactions() { - if !txscript.IsFinalizedTransaction(tx.MsgTx(), blockHeight, + if !IsFinalizedTransaction(tx, blockHeight, header.Timestamp) { str := fmt.Sprintf("block contains unfinalized "+ diff --git a/mempool.go b/mempool.go index ada0db59..ebcaf5f7 100644 --- a/mempool.go +++ b/mempool.go @@ -237,7 +237,7 @@ func (mp *txMemPool) checkTransactionStandard(tx *btcutil.Tx, height int64) erro // The transaction must be finalized to be standard and therefore // considered for inclusion in a block. adjustedTime := mp.server.timeSource.AdjustedTime() - if !txscript.IsFinalizedTransaction(tx.MsgTx(), height, adjustedTime) { + if !blockchain.IsFinalizedTransaction(tx, height, adjustedTime) { return txRuleError(wire.RejectNonstandard, "transaction is not finalized") } diff --git a/mining.go b/mining.go index 0b739111..4af91138 100644 --- a/mining.go +++ b/mining.go @@ -446,7 +446,7 @@ mempoolLoop: minrLog.Tracef("Skipping coinbase tx %s", tx.Sha()) continue } - if !txscript.IsFinalizedTransaction(tx.MsgTx(), nextBlockHeight, + if !blockchain.IsFinalizedTransaction(tx, nextBlockHeight, timeSource.AdjustedTime()) { minrLog.Tracef("Skipping non-finalized tx %s", tx.Sha()) diff --git a/txscript/consensus.go b/txscript/consensus.go index de73389c..1aec5028 100644 --- a/txscript/consensus.go +++ b/txscript/consensus.go @@ -4,13 +4,6 @@ package txscript -import ( - "math" - "time" - - "github.com/btcsuite/btcd/wire" -) - const ( // LockTimeThreshold is the number below which a lock time is // interpreted to be a block number. Since an average of one block @@ -19,36 +12,3 @@ const ( // the lock time is a uint32, the max is sometime around 2106. LockTimeThreshold uint32 = 5e8 // Tue Nov 5 00:53:20 1985 UTC ) - -// IsFinalizedTransaction determines whether or not a transaction is finalized. -func IsFinalizedTransaction(msgTx *wire.MsgTx, blockHeight int64, blockTime time.Time) bool { - // Lock time of zero means the transaction is finalized. - lockTime := msgTx.LockTime - if lockTime == 0 { - return true - } - - // The lock time field of a transaction is either a block height at - // which the transaction is finalized or a timestamp depending on if the - // value is before the LockTimeThreshold. When it is under the - // threshold it is a block height. - blockTimeOrHeight := int64(0) - if lockTime < LockTimeThreshold { - blockTimeOrHeight = blockHeight - } else { - blockTimeOrHeight = blockTime.Unix() - } - if int64(lockTime) < blockTimeOrHeight { - return true - } - - // At this point, the transaction's lock time hasn't occured yet, but - // the transaction might still be finalized if the sequence number - // for all transaction inputs is maxed out. - for _, txIn := range msgTx.TxIn { - if txIn.Sequence != math.MaxUint32 { - return false - } - } - return true -} From e13b4febecbc379738fb9f4ea74c98de70d92e97 Mon Sep 17 00:00:00 2001 From: David Hill Date: Mon, 13 Jul 2015 12:52:17 -0400 Subject: [PATCH 06/27] Document limitfreerelay and norelaypriority options. --- doc.go | 2 ++ sample-btcd.conf | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/doc.go b/doc.go index d98cd830..660b158d 100644 --- a/doc.go +++ b/doc.go @@ -82,6 +82,8 @@ Application Options: --limitfreerelay= Limit relay of transactions with no transaction fee to the given amount in thousands of bytes per minute (15) + --norelaypriority Do not require free or low-fee transactions to have + high priority for relaying --maxorphantx= Max number of orphan transactions to keep in memory (1000) --generate= Generate (mine) bitcoins using the CPU diff --git a/sample-btcd.conf b/sample-btcd.conf index 515a1fc9..ee873b5e 100644 --- a/sample-btcd.conf +++ b/sample-btcd.conf @@ -211,6 +211,14 @@ ; ------------------------------------------------------------------------------ ; Mempool Settings - The following options ; ------------------------------------------------------------------------------ + +; Rate-limit free transactions to the value 15 * 1000 bytes per +; minute. +; limitfreerelay=15 + +; Require high priority for relaying free or low-fee transactions. +; norelaypriority=0 + ; Limit orphan transaction pool to 1000 transactions. ; maxorphantx=1000 From 8fcea82a568cac918238ba6f196de81a01f4d887 Mon Sep 17 00:00:00 2001 From: Jonathan Gillham Date: Sun, 19 Jul 2015 16:15:29 +0100 Subject: [PATCH 07/27] Fixed erroneous txscript.KeyClosure documentation. --- txscript/sign.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/txscript/sign.go b/txscript/sign.go index df8afeb3..b2082be3 100644 --- a/txscript/sign.go +++ b/txscript/sign.go @@ -346,10 +346,10 @@ type KeyDB interface { GetKey(btcutil.Address) (*btcec.PrivateKey, bool, error) } -// KeyClosure implements ScriptDB with a closure +// KeyClosure implements KeyDB with a closure. type KeyClosure func(btcutil.Address) (*btcec.PrivateKey, bool, error) -// GetKey implements KeyDB by returning the result of calling the closure +// GetKey implements KeyDB by returning the result of calling the closure. func (kc KeyClosure) GetKey(address btcutil.Address) (*btcec.PrivateKey, bool, error) { return kc(address) @@ -361,10 +361,10 @@ type ScriptDB interface { GetScript(btcutil.Address) ([]byte, error) } -// ScriptClosure implements ScriptDB with a closure +// ScriptClosure implements ScriptDB with a closure. type ScriptClosure func(btcutil.Address) ([]byte, error) -// GetScript implements ScriptDB by returning the result of calling the closure +// GetScript implements ScriptDB by returning the result of calling the closure. func (sc ScriptClosure) GetScript(address btcutil.Address) ([]byte, error) { return sc(address) } From 4335ce828c90a0bbea89686dbad008a7a43220b6 Mon Sep 17 00:00:00 2001 From: Bruno Date: Mon, 20 Jul 2015 14:26:05 +0800 Subject: [PATCH 08/27] switch maxDataCarrierSize to public const --- txscript/standard.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/txscript/standard.go b/txscript/standard.go index 71349248..77219e42 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -10,9 +10,9 @@ import ( ) const ( - // maxDataCarrierSize is the maximum number of bytes allowed in pushed + // MaxDataCarrierSize is the maximum number of bytes allowed in pushed // data to be considered a nulldata transaction - maxDataCarrierSize = 80 + MaxDataCarrierSize = 80 // StandardVerifyFlags are the script flags which are used when // executing transaction scripts to enforce additional checks which @@ -120,7 +120,7 @@ func isMultiSig(pops []parsedOpcode) bool { func isNullData(pops []parsedOpcode) bool { // A nulldata transaction is either a single OP_RETURN or an // OP_RETURN SMALLDATA (where SMALLDATA is a data push up to - // maxDataCarrierSize bytes). + // MaxDataCarrierSize bytes). l := len(pops) if l == 1 && pops[0].opcode.value == OP_RETURN { return true @@ -129,7 +129,7 @@ func isNullData(pops []parsedOpcode) bool { return l == 2 && pops[0].opcode.value == OP_RETURN && pops[1].opcode.value <= OP_PUSHDATA4 && - len(pops[1].data) <= maxDataCarrierSize + len(pops[1].data) <= MaxDataCarrierSize } // scriptType returns the type of the script being inspected from the known From 7246b9b933ff7f7d6ba5fe015e67ee3dbcb3d16c Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 29 Jun 2015 23:02:56 -0500 Subject: [PATCH 09/27] docs: Correct JSON-RPC API overview return links. This commit corrects the JSON-RPC API doc return to overview links for the Websocket Extension Method Details section. --- docs/json_rpc_api.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/json_rpc_api.md b/docs/json_rpc_api.md index 7c1192ef..a07f98c9 100644 --- a/docs/json_rpc_api.md +++ b/docs/json_rpc_api.md @@ -682,7 +682,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|1. username (string, required)
2. passphrase (string, required)| |Description|Authenticate the connection against the username and password configured for the RPC server.
Invoking any other method before authenticating with this command will close the connection.
NOTE: This is only required if an HTTP Authorization header is not being used.| |Returns|Success: Nothing
Failure: Nothing (websocket disconnected)| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
*** @@ -695,7 +695,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|None| |Description|Request notifications for whenever a block is connected or disconnected from the main (best) chain.
NOTE: If a client subscribes to both block and transaction (recvtx and redeemingtx) notifications, the blockconnected notification will be sent after all transaction notifications have been sent. This allows clients to know when all relevant transactions for a block have been received.| |Returns|Nothing| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
***
@@ -707,7 +707,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|None| |Description|Cancel sending notifications for whenever a block is connected or disconnected from the main (best) chain.| |Returns|Nothing| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
*** @@ -720,7 +720,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|1. Addresses (JSON array, required)
 `[ (json array of strings)`
  `"bitcoinaddress", (string) the bitcoin address`
  `...`
 `]`| |Description|Send a recvtx notification when a transaction added to mempool or appears in a newly-attached block contains a txout pkScript sending to any of the passed addresses. Matching outpoints are automatically registered for redeemingtx notifications.| |Returns|Nothing| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
*** @@ -733,7 +733,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|1. Addresses (JSON array, required)
 `[ (json array of strings)`
  `"bitcoinaddress", (string) the bitcoin address`
  `...`
 `]`| |Description|Cancel registered receive notifications for each passed address.| |Returns|Nothing| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
*** @@ -746,7 +746,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|1. Outpoints (JSON array, required)
 `[ (JSON array)`
  `{ (JSON object)`
   `"hash":"data", (string) the hex-encoded bytes of the outpoint hash`
   `"index":n (numeric) the txout index of the outpoint`
  `},`
  `...`
 `]`| |Description|Send a redeemingtx notification when a transaction spending an outpoint appears in mempool (if relayed to this btcd instance) and when such a transaction first appears in a newly-attached block.| |Returns|Nothing| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
*** @@ -759,7 +759,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|1. Outpoints (JSON array, required)
 `[ (JSON array)`
  `{ (JSON object)`
   `"hash":"data", (string) the hex-encoded bytes of the outpoint hash`
   `"index":n (numeric) the txout index of the outpoint`
  `},`
  `...`
 `]`| |Description|Cancel registered spending notifications for each passed outpoint.| |Returns|Nothing| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
*** @@ -772,7 +772,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|1. BeginBlock (string, required) block hash to begin rescanning from
2. Addresses (JSON array, required)
 `[ (json array of strings)`
  `"bitcoinaddress", (string) the bitcoin address`
  `...`
 `]`
3. Outpoints (JSON array, required)
 `[ (JSON array)`
  `{ (JSON object)`
   `"hash":"data", (string) the hex-encoded bytes of the outpoint hash`
   `"index":n (numeric) the txout index of the outpoint`
  `},`
  `...`
 `]`
4. EndBlock (string, optional) hash of final block to rescan| |Description|Rescan block chain for transactions to addresses, starting at block BeginBlock and ending at EndBlock. The current known UTXO set for all passed addresses at height BeginBlock should included in the Outpoints argument. If EndBlock is omitted, the rescan continues through the best block in the main chain. Additionally, if no EndBlock is provided, the client is automatically registered for transaction notifications for all rescanned addresses and the final UTXO set. Rescan results are sent as recvtx and redeemingtx notifications. This call returns once the rescan completes.| |Returns|Nothing| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
*** @@ -785,7 +785,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|1. verbose (boolean, optional, default=false) - specifies which type of notification to receive. If verbose is true, then the caller receives [txacceptedverbose](#txacceptedverbose), otherwise the caller receives [txaccepted](#txaccepted)| |Description|Send either a [txaccepted](#txaccepted) or a [txacceptedverbose](#txacceptedverbose) notification when a new transaction is accepted into the mempool.| |Returns|Nothing| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
*** @@ -798,7 +798,7 @@ user. Click the method name for further details such as parameter and return in |Parameters|None| |Description|Stop sending either a [txaccepted](#txaccepted) or a [txacceptedverbose](#txacceptedverbose) notification when a new transaction is accepted into the mempool.| |Returns|Nothing| -[Return to Overview](#ExtensionRequestOverview)
+[Return to Overview](#WSExtMethodOverview)
From 1ddf8e8edf0b0de7da442c106058181aa5692217 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 18 Jul 2015 18:15:36 -0500 Subject: [PATCH 10/27] Correct reconnect handling for persistent peers. This commit correctly replaces persistent peers that are being retried in the list of persistent peers so it will continue to be retried as intended. Also, limit the maximum retry interval for persistent peers to 5 minutes. Fixes #463. --- peer.go | 14 ++++++++++++++ server.go | 6 ++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/peer.go b/peer.go index eed6c552..a8aaf204 100644 --- a/peer.go +++ b/peer.go @@ -53,6 +53,17 @@ const ( // pingTimeoutMinutes is the number of minutes since we last sent a // message requiring a reply before we will ping a host. pingTimeoutMinutes = 2 + + // connectionRetryInterval is the base amount of time to wait in between + // retries when connecting to persistent peers. It is adjusted by the + // number of retries such that there is a retry backoff. + connectionRetryInterval = time.Second * 10 + + // maxConnectionRetryInterval is the max amount of time retrying of a + // persistent peer is allowed to grow to. This is necessary since the + // retry logic uses a backoff mechanism which increases the interval + // base done the number of retries that have been done. + maxConnectionRetryInterval = time.Minute * 5 ) var ( @@ -2015,6 +2026,9 @@ func newOutboundPeer(s *server, addr string, persistent bool, retryCount int64) if p.retryCount > 0 { scaledInterval := connectionRetryInterval.Nanoseconds() * p.retryCount / 2 scaledDuration := time.Duration(scaledInterval) + if scaledDuration > maxConnectionRetryInterval { + scaledDuration = maxConnectionRetryInterval + } srvrLog.Debugf("Retrying connection to %s in %s", addr, scaledDuration) time.Sleep(scaledDuration) } diff --git a/server.go b/server.go index 345d64ea..474efca0 100644 --- a/server.go +++ b/server.go @@ -39,10 +39,6 @@ const ( // server. supportedServices = wire.SFNodeNetwork - // connectionRetryInterval is the amount of time to wait in between - // retries when connecting to persistent peers. - connectionRetryInterval = time.Second * 10 - // defaultMaxOutbound is the default number of max outbound peers. defaultMaxOutbound = 8 ) @@ -307,7 +303,9 @@ func (s *server) handleDonePeerMsg(state *peerState, p *peer) { // Issue an asynchronous reconnect if the peer was a // persistent outbound connection. if !p.inbound && p.persistent && atomic.LoadInt32(&s.shutdown) == 0 { + delete(list, e) e = newOutboundPeer(s, p.addr, true, p.retryCount+1) + list[e] = struct{}{} return } if !p.inbound { From 8a4a875e9d4d113ebab25b22e97050508fa810d8 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 2 Jun 2015 14:21:18 -0400 Subject: [PATCH 11/27] Ignore getheaders requests if not synced. This mimics Bitcoin Core commit a1ba0778dd3c784046dea334e5d39f37eca264f7 --- peer.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/peer.go b/peer.go index a8aaf204..68b782e9 100644 --- a/peer.go +++ b/peer.go @@ -1012,6 +1012,11 @@ func (p *peer) handleGetBlocksMsg(msg *wire.MsgGetBlocks) { // handleGetHeadersMsg is invoked when a peer receives a getheaders bitcoin // message. func (p *peer) handleGetHeadersMsg(msg *wire.MsgGetHeaders) { + // Ignore getheaders requests if not in sync. + if !p.server.blockManager.IsCurrent() { + return + } + // Attempt to look up the height of the provided stop hash. endIdx := database.AllShas height, err := p.server.db.FetchBlockHeightBySha(&msg.HashStop) From 6f1272e767f3a02845d7189a619371c2aab8fb98 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Wed, 27 May 2015 11:16:19 -0400 Subject: [PATCH 12/27] btcjson: Add spendable to listunspent result. --- btcjson/walletsvrresults.go | 1 + 1 file changed, 1 insertion(+) diff --git a/btcjson/walletsvrresults.go b/btcjson/walletsvrresults.go index 91c80682..2f7d80c6 100644 --- a/btcjson/walletsvrresults.go +++ b/btcjson/walletsvrresults.go @@ -113,6 +113,7 @@ type ListUnspentResult struct { RedeemScript string `json:"redeemScript,omitempty"` Amount float64 `json:"amount"` Confirmations int64 `json:"confirmations"` + Spendable bool `json:"spendable"` } // SignRawTransactionError models the data that contains script verification From 3d89b56b27c35597089f28b453c13701479b1a48 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 22 Jul 2015 09:24:36 -0500 Subject: [PATCH 13/27] wire: Update tests to force error in tx lock time. This commit updates the wire tests for transactions which force serialization and deserialization errors to force an error in the the transaction lock time path. This brings the wire test coverage back up to 100%. --- wire/msgtx_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wire/msgtx_test.go b/wire/msgtx_test.go index 2e4e2030..aedc7a29 100644 --- a/wire/msgtx_test.go +++ b/wire/msgtx_test.go @@ -348,7 +348,7 @@ func TestTxWireErrors(t *testing.T) { // Force error in transaction output pk script. {multiTx, multiTxEncoded, pver, 63, io.ErrShortWrite, io.EOF}, // Force error in transaction output lock time. - {multiTx, multiTxEncoded, pver, 130, io.ErrShortWrite, io.EOF}, + {multiTx, multiTxEncoded, pver, 206, io.ErrShortWrite, io.EOF}, } t.Logf("Running %d tests", len(tests)) @@ -493,7 +493,7 @@ func TestTxSerializeErrors(t *testing.T) { // Force error in transaction output pk script. {multiTx, multiTxEncoded, 63, io.ErrShortWrite, io.EOF}, // Force error in transaction output lock time. - {multiTx, multiTxEncoded, 130, io.ErrShortWrite, io.EOF}, + {multiTx, multiTxEncoded, 206, io.ErrShortWrite, io.EOF}, } t.Logf("Running %d tests", len(tests)) From eb4ad095982b0c359fbb17d240e69685e00b9933 Mon Sep 17 00:00:00 2001 From: David Hill Date: Thu, 9 Jul 2015 11:50:03 -0400 Subject: [PATCH 14/27] Implmement BlockHeader BtcEncode/BtcDecode. At the current time, there is no difference between the wire encoding at protocol version 0 and the stable long-term storage format. These methods are simply for consistency with the other types. --- wire/blockheader.go | 16 ++++++++++++++++ wire/blockheader_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/wire/blockheader.go b/wire/blockheader.go index 145ab452..e5d9e391 100644 --- a/wire/blockheader.go +++ b/wire/blockheader.go @@ -56,6 +56,22 @@ func (h *BlockHeader) BlockSha() ShaHash { return DoubleSha256SH(buf.Bytes()) } +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +// See Deserialize for decoding block headers stored to disk, such as in a +// database, as opposed to decoding block headers from the wire. +func (h *BlockHeader) BtcDecode(r io.Reader, pver uint32) error { + return readBlockHeader(r, pver, h) +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +// See Serialize for encoding block headers to be stored to disk, such as in a +// database, as opposed to encoding block headers for the wire. +func (h *BlockHeader) BtcEncode(w io.Writer, pver uint32) error { + return writeBlockHeader(w, pver, h) +} + // Deserialize decodes a block header from r into the receiver using a format // that is suitable for long-term storage such as a database while respecting // the Version field. diff --git a/wire/blockheader_test.go b/wire/blockheader_test.go index dfbcb1a8..c6d76bfd 100644 --- a/wire/blockheader_test.go +++ b/wire/blockheader_test.go @@ -50,6 +50,7 @@ func TestBlockHeader(t *testing.T) { // protocol versions. func TestBlockHeaderWire(t *testing.T) { nonce := uint32(123123) // 0x1e0f3 + pver := uint32(70001) // baseBlockHdr is used in the various tests as a baseline BlockHeader. bits := uint32(0x1d00ffff) @@ -140,6 +141,18 @@ func TestBlockHeaderWire(t *testing.T) { continue } + buf.Reset() + err = test.in.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("BtcEncode #%d error %v", i, err) + continue + } + if !bytes.Equal(buf.Bytes(), test.buf) { + t.Errorf("BtcEncode #%d\n got: %s want: %s", i, + spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) + continue + } + // Decode the block header from wire format. var bh wire.BlockHeader rbuf := bytes.NewReader(test.buf) @@ -153,6 +166,18 @@ func TestBlockHeaderWire(t *testing.T) { spew.Sdump(&bh), spew.Sdump(test.out)) continue } + + rbuf = bytes.NewReader(test.buf) + err = bh.BtcDecode(rbuf, pver) + if err != nil { + t.Errorf("BtcDecode #%d error %v", i, err) + continue + } + if !reflect.DeepEqual(&bh, test.out) { + t.Errorf("BtcDecode #%d\n got: %s want: %s", i, + spew.Sdump(&bh), spew.Sdump(test.out)) + continue + } } } From a6c79c7a913b1f9f5e0a7c2aa9c6416ecd430c84 Mon Sep 17 00:00:00 2001 From: David Hill Date: Sat, 4 Jul 2015 13:42:43 -0400 Subject: [PATCH 15/27] Implement getblockheader RPC. This mimics Bitcoin Core commit 076badb60f33f0c32b035de220ca14c52a423a2a --- btcjson/chainsvrcmds.go | 16 +++++++++ btcjson/chainsvrcmds_test.go | 15 ++++++++ btcjson/chainsvrresults.go | 17 ++++++++++ docs/json_rpc_api.md | 57 +++++++++++++++++++------------ rpcserver.go | 66 ++++++++++++++++++++++++++++++++++++ rpcserverhelp.go | 22 ++++++++++++ 6 files changed, 172 insertions(+), 21 deletions(-) diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index 69a81f12..11bdf27e 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -172,6 +172,21 @@ func NewGetBlockHashCmd(index int64) *GetBlockHashCmd { } } +// GetBlockHeaderCmd defines the getblockheader JSON-RPC command. +type GetBlockHeaderCmd struct { + Hash string + Verbose *bool `jsonrpcdefault:"true"` +} + +// NewGetBlockHeaderCmd returns a new instance which can be used to issue a +// getblockheader JSON-RPC command. +func NewGetBlockHeaderCmd(hash string, verbose *bool) *GetBlockHeaderCmd { + return &GetBlockHeaderCmd{ + Hash: hash, + Verbose: verbose, + } +} + // TemplateRequest is a request object as defined in BIP22 // (https://en.bitcoin.it/wiki/BIP_0022), it is optionally provided as an // pointer argument to GetBlockTemplateCmd. @@ -695,6 +710,7 @@ func init() { MustRegisterCmd("getblockchaininfo", (*GetBlockChainInfoCmd)(nil), flags) MustRegisterCmd("getblockcount", (*GetBlockCountCmd)(nil), flags) MustRegisterCmd("getblockhash", (*GetBlockHashCmd)(nil), flags) + MustRegisterCmd("getblockheader", (*GetBlockHeaderCmd)(nil), flags) MustRegisterCmd("getblocktemplate", (*GetBlockTemplateCmd)(nil), flags) MustRegisterCmd("getchaintips", (*GetChainTipsCmd)(nil), flags) MustRegisterCmd("getconnectioncount", (*GetConnectionCountCmd)(nil), flags) diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go index 38021524..baaf7233 100644 --- a/btcjson/chainsvrcmds_test.go +++ b/btcjson/chainsvrcmds_test.go @@ -199,6 +199,20 @@ func TestChainSvrCmds(t *testing.T) { marshalled: `{"jsonrpc":"1.0","method":"getblockhash","params":[123],"id":1}`, unmarshalled: &btcjson.GetBlockHashCmd{Index: 123}, }, + { + name: "getblockheader", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getblockheader", "123") + }, + staticCmd: func() interface{} { + return btcjson.NewGetBlockHeaderCmd("123", nil) + }, + marshalled: `{"jsonrpc":"1.0","method":"getblockheader","params":["123"],"id":1}`, + unmarshalled: &btcjson.GetBlockHeaderCmd{ + Hash: "123", + Verbose: btcjson.Bool(true), + }, + }, { name: "getblocktemplate", newCmd: func() (interface{}, error) { @@ -926,6 +940,7 @@ func TestChainSvrCmds(t *testing.T) { t.Errorf("Test #%d (%s) unexpected marshalled data - "+ "got %s, want %s", i, test.name, marshalled, test.marshalled) + t.Errorf("\n%s\n%s", marshalled, test.marshalled) continue } diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index c0efd7cd..518d78fe 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -6,6 +6,23 @@ package btcjson import "encoding/json" +// GetBlockHeaderVerboseResult models the data from the getblockheader command when +// the verbose flag is set. When the verbose flag is not set, getblockheader +// returns a hex-encoded string. +type GetBlockHeaderVerboseResult struct { + Hash string `json:"hash"` + Confirmations uint64 `json:"confirmations"` + Height int32 `json:"height"` + Version int32 `json:"version"` + MerkleRoot string `json:"merkleroot"` + Time int64 `json:"time"` + Nonce uint64 `json:"nonce"` + Bits string `json:"bits"` + Difficulty float64 `json:"difficulty"` + PreviousHash string `json:"previousblockhash,omitempty"` + NextHash string `json:"nextblockhash,omitempty"` +} + // GetBlockVerboseResult models the data from the getblock command when the // verbose flag is set. When the verbose flag is not set, getblock returns a // hex-encoded string. diff --git a/docs/json_rpc_api.md b/docs/json_rpc_api.md index a07f98c9..bf95a845 100644 --- a/docs/json_rpc_api.md +++ b/docs/json_rpc_api.md @@ -157,27 +157,28 @@ the method name for further details such as parameter and return information. |7|[getblock](#getblock)|Y|Returns information about a block given its hash.| |8|[getblockcount](#getblockcount)|Y|Returns the number of blocks in the longest block chain.| |9|[getblockhash](#getblockhash)|Y|Returns hash of the block in best block chain at the given height.| -|10|[getconnectioncount](#getconnectioncount)|N|Returns the number of active connections to other peers.| -|11|[getdifficulty](#getdifficulty)|Y|Returns the proof-of-work difficulty as a multiple of the minimum difficulty.| -|12|[getgenerate](#getgenerate)|N|Return if the server is set to generate coins (mine) or not.| -|13|[gethashespersec](#gethashespersec)|N|Returns a recent hashes per second performance measurement while generating coins (mining).| -|14|[getinfo](#getinfo)|Y|Returns a JSON object containing various state info.| -|15|[getmempoolinfo](#getmempoolinfo)|N|Returns a JSON object containing mempool-related information.| -|16|[getmininginfo](#getmininginfo)|N|Returns a JSON object containing mining-related information.| -|17|[getnettotals](#getnettotals)|Y|Returns a JSON object containing network traffic statistics.| -|18|[getnetworkhashps](#getnetworkhashps)|Y|Returns the estimated network hashes per second for the block heights provided by the parameters.| -|19|[getpeerinfo](#getpeerinfo)|N|Returns information about each connected network peer as an array of json objects.| -|20|[getrawmempool](#getrawmempool)|Y|Returns an array of hashes for all of the transactions currently in the memory pool.| -|21|[getrawtransaction](#getrawtransaction)|Y|Returns information about a transaction given its hash.| -|22|[getwork](#getwork)|N|Returns formatted hash data to work on or checks and submits solved data.
NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.| -|23|[help](#help)|Y|Returns a list of all commands or help for a specified command.| -|24|[ping](#ping)|N|Queues a ping to be sent to each connected peer.| -|25|[sendrawtransaction](#sendrawtransaction)|Y|Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.
btcd does not yet implement the `allowhighfees` parameter, so it has no effect| -|26|[setgenerate](#setgenerate) |N|Set the server to generate coins (mine) or not.
NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.| -|27|[stop](#stop)|N|Shutdown btcd.| -|28|[submitblock](#submitblock)|Y|Attempts to submit a new serialized, hex-encoded block to the network.| -|29|[validateaddress](#validateaddress)|Y|Verifies the given address is valid. NOTE: Since btcd does not have a wallet integrated, btcd will only return whether the address is valid or not.| -|30|[verifychain](#verifychain)|N|Verifies the block chain database.| +|10|[getblockheader](#getblockheader)|Y|Returns the block header of the block.| +|11|[getconnectioncount](#getconnectioncount)|N|Returns the number of active connections to other peers.| +|12|[getdifficulty](#getdifficulty)|Y|Returns the proof-of-work difficulty as a multiple of the minimum difficulty.| +|13|[getgenerate](#getgenerate)|N|Return if the server is set to generate coins (mine) or not.| +|14|[gethashespersec](#gethashespersec)|N|Returns a recent hashes per second performance measurement while generating coins (mining).| +|15|[getinfo](#getinfo)|Y|Returns a JSON object containing various state info.| +|16|[getmempoolinfo](#getmempoolinfo)|N|Returns a JSON object containing mempool-related information.| +|17|[getmininginfo](#getmininginfo)|N|Returns a JSON object containing mining-related information.| +|18|[getnettotals](#getnettotals)|Y|Returns a JSON object containing network traffic statistics.| +|19|[getnetworkhashps](#getnetworkhashps)|Y|Returns the estimated network hashes per second for the block heights provided by the parameters.| +|20|[getpeerinfo](#getpeerinfo)|N|Returns information about each connected network peer as an array of json objects.| +|21|[getrawmempool](#getrawmempool)|Y|Returns an array of hashes for all of the transactions currently in the memory pool.| +|22|[getrawtransaction](#getrawtransaction)|Y|Returns information about a transaction given its hash.| +|23|[getwork](#getwork)|N|Returns formatted hash data to work on or checks and submits solved data.
NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.| +|24|[help](#help)|Y|Returns a list of all commands or help for a specified command.| +|25|[ping](#ping)|N|Queues a ping to be sent to each connected peer.| +|26|[sendrawtransaction](#sendrawtransaction)|Y|Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.
btcd does not yet implement the `allowhighfees` parameter, so it has no effect| +|27|[setgenerate](#setgenerate) |N|Set the server to generate coins (mine) or not.
NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.| +|28|[stop](#stop)|N|Shutdown btcd.| +|29|[submitblock](#submitblock)|Y|Attempts to submit a new serialized, hex-encoded block to the network.| +|30|[validateaddress](#validateaddress)|Y|Verifies the given address is valid. NOTE: Since btcd does not have a wallet integrated, btcd will only return whether the address is valid or not.| +|31|[verifychain](#verifychain)|N|Verifies the block chain database.|
**5.2 Method Details**
@@ -295,6 +296,20 @@ the method name for further details such as parameter and return information. [Return to Overview](#MethodOverview)
*** +
+ +| | | +|---|---| +|Method|getblockheader| +|Parameters|1. block hash (string, required) - the hash of the block
2. verbose (boolean, optional, default=true) - specifies the block header is returned as a JSON object instead of a hex-encoded string| +|Description|Returns hex-encoded bytes of the serialized block header.| +|Returns (verbose=false)|`"data" (string) hex-encoded bytes of the serialized block`| +|Returns (verbose=true)|`{ (json object)`
  `"hash": "blockhash", (string) the hash of the block (same as provided)`
  `"confirmations": n, (numeric) the number of confirmations`
  `"height": n, (numeric) the height of the block in the block chain`
  `"version": n, (numeric) the block version`
  `"merkleroot": "hash", (string) root hash of the merkle tree`
  `"time": n, (numeric) the block time in seconds since 1 Jan 1970 GMT`
  `"nonce": n, (numeric) the block nonce`
  `"bits": n, (numeric) the bits which represent the block difficulty`
  `"difficulty": n.nn, (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty`
  `"previousblockhash": "hash", (string) the hash of the previous block`
  `"nextblockhash": "hash", (string) the hash of the next block (only if there is one)`
`}`| +|Example Return (verbose=false)|`"0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc564900000000`
`38ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc0552`
`27f1001c29c1ea3b"`
**Newlines added for display purposes. The actual return does not contain newlines.**| +|Example Return (verbose=true)|`{`
  `"hash": "00000000009e2958c15ff9290d571bf9459e93b19765c6801ddeccadbb160a1e",`
  `"confirmations": 392076,`
  `"height": 100000,`
  `"version": 2,`
  `"merkleroot": "d574f343976d8e70d91cb278d21044dd8a396019e6db70755a0a50e4783dba38",`
  `"time": 1376123972,`
  `"nonce": 1005240617,`
  `"bits": "1c00f127",`
  `"difficulty": 271.75767393,`
  `"previousblockhash": "000000004956cc2edd1a8caa05eacfa3c69f4c490bfc9ace820257834115ab35",`
  `"nextblockhash": "0000000000629d100db387f37d0f37c51118f250fb0946310a8c37316cbc4028"`
`}`| +[Return to Overview](#MethodOverview)
+ +***
| | | diff --git a/rpcserver.go b/rpcserver.go index 58fcf657..1672ee20 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -139,6 +139,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "getblock": handleGetBlock, "getblockcount": handleGetBlockCount, "getblockhash": handleGetBlockHash, + "getblockheader": handleGetBlockHeader, "getblocktemplate": handleGetBlockTemplate, "getconnectioncount": handleGetConnectionCount, "getcurrentnet": handleGetCurrentNet, @@ -1089,6 +1090,71 @@ func handleGetBlockHash(s *rpcServer, cmd interface{}, closeChan <-chan struct{} return sha.String(), nil } +// handleGetBlockHeader implements the getblockheader command. +func handleGetBlockHeader(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + c := cmd.(*btcjson.GetBlockHeaderCmd) + + sha, err := wire.NewShaHashFromStr(c.Hash) + if err != nil { + return nil, err + } + + if c.Verbose == nil || *c.Verbose { + blk, err := s.server.db.FetchBlockBySha(sha) + if err != nil { + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCInvalidAddressOrKey, + Message: "Invalid address or key: " + err.Error(), + } + } + + _, maxIdx, err := s.server.db.NewestSha() + if err != nil { + context := "Failed to get newest hash" + return nil, internalRPCError(err.Error(), context) + } + + var shaNextStr string + shaNext, err := s.server.db.FetchBlockShaByHeight(int64(blk.Height() + 1)) + if err == nil { + shaNextStr = shaNext.String() + } + + msgBlock := blk.MsgBlock() + blockHeaderReply := btcjson.GetBlockHeaderVerboseResult{ + Hash: c.Hash, + Confirmations: uint64(1 + maxIdx - blk.Height()), + Height: int32(blk.Height()), + Version: msgBlock.Header.Version, + MerkleRoot: msgBlock.Header.MerkleRoot.String(), + NextHash: shaNextStr, + PreviousHash: msgBlock.Header.PrevBlock.String(), + Nonce: uint64(msgBlock.Header.Nonce), + Time: msgBlock.Header.Timestamp.Unix(), + Bits: strconv.FormatInt(int64(msgBlock.Header.Bits), 16), + Difficulty: getDifficultyRatio(msgBlock.Header.Bits), + } + return blockHeaderReply, nil + } + + // Verbose disabled + blkHeader, err := s.server.db.FetchBlockHeaderBySha(sha) + if err != nil { + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCInvalidAddressOrKey, + Message: "Invalid address or key: " + err.Error(), + } + } + + buf := bytes.NewBuffer(make([]byte, 0, wire.MaxBlockHeaderPayload)) + if err = blkHeader.BtcEncode(buf, maxProtocolVersion); err != nil { + errStr := fmt.Sprintf("Failed to serialize data: %v", err) + return nil, internalRPCError(errStr, "") + } + + return hex.EncodeToString(buf.Bytes()), nil +} + // encodeTemplateID encodes the passed details into an ID that can be used to // uniquely identify a block template. func encodeTemplateID(prevHash *wire.ShaHash, lastGenerated time.Time) string { diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 4f44b8e9..368c2b11 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -180,6 +180,27 @@ var helpDescsEnUS = map[string]string{ "getblockhash-index": "The block height", "getblockhash--result0": "The block hash", + // GetBlockHeaderCmd help. + "getblockheader--synopsis": "Returns information about a block header given its hash.", + "getblockheader-hash": "The hash of the block", + "getblockheader-verbose": "Specifies the block header is returned as a JSON object instead of hex-encoded string", + "getblockheader--condition0": "verbose=false", + "getblockheader--condition1": "verbose=true", + "getblockheader--result0": "The block header hash", + + // GetBlockHeaderVerboseResult help. + "getblockheaderverboseresult-hash": "The hash of the block (same as provided)", + "getblockheaderverboseresult-confirmations": "The number of confirmations", + "getblockheaderverboseresult-height": "The height of the block in the block chain", + "getblockheaderverboseresult-version": "The block version", + "getblockheaderverboseresult-merkleroot": "Root hash of the merkle tree", + "getblockheaderverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT", + "getblockheaderverboseresult-nonce": "The block nonce", + "getblockheaderverboseresult-bits": "The bits which represent the block difficulty", + "getblockheaderverboseresult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty", + "getblockheaderverboseresult-previousblockhash": "The hash of the previous block", + "getblockheaderverboseresult-nextblockhash": "The hash of the next block (only if there is one)", + // TemplateRequest help. "templaterequest-mode": "This is 'template', 'proposal', or omitted", "templaterequest-capabilities": "List of capabilities", @@ -540,6 +561,7 @@ var rpcResultTypes = map[string][]interface{}{ "getblock": []interface{}{(*string)(nil), (*btcjson.GetBlockVerboseResult)(nil)}, "getblockcount": []interface{}{(*int64)(nil)}, "getblockhash": []interface{}{(*string)(nil)}, + "getblockheader": []interface{}{(*string)(nil), (*btcjson.GetBlockHeaderVerboseResult)(nil)}, "getblocktemplate": []interface{}{(*btcjson.GetBlockTemplateResult)(nil), (*string)(nil), nil}, "getconnectioncount": []interface{}{(*int32)(nil)}, "getcurrentnet": []interface{}{(*uint32)(nil)}, From 5ab891177b487be749eb8a21e9a77c02a8196fb5 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 24 Jul 2015 09:23:46 -0500 Subject: [PATCH 16/27] docs: Remove outdated btcws link from README.md. --- docs/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 113156aa..5f855846 100644 --- a/docs/README.md +++ b/docs/README.md @@ -201,9 +201,6 @@ information. robust and easy to use Websocket-enabled Bitcoin JSON-RPC client * [btcjson](https://github.com/btcsuite/btcjson) - Provides an extensive API for the underlying JSON-RPC command and return values - * [btcws](https://github.com/btcsuite/btcws) - Custom types for btcd - websocket extension commands (registers the extension commands with - [btcjson](https://github.com/btcsuite/btcjson)) * [wire](https://github.com/btcsuite/btcd/tree/master/wire) - Implements the Bitcoin wire protocol * [blockchain](https://github.com/btcsuite/btcd/tree/master/blockchain) - From b1606447b55a1a4d921378ee6466111df3c04632 Mon Sep 17 00:00:00 2001 From: drazisil Date: Fri, 24 Jul 2015 13:56:24 -0400 Subject: [PATCH 17/27] added getwalletinfo cmd --- btcjson/walletsvrcmds.go | 10 ++++++++++ btcjson/walletsvrcmds_test.go | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/btcjson/walletsvrcmds.go b/btcjson/walletsvrcmds.go index 2b977404..f340714b 100644 --- a/btcjson/walletsvrcmds.go +++ b/btcjson/walletsvrcmds.go @@ -237,6 +237,15 @@ func NewGetTransactionCmd(txHash string, includeWatchOnly *bool) *GetTransaction } } +// GetWalletInfoCmd defines the getwalletinfo JSON-RPC command. +type GetWalletInfoCmd struct{} + +// NewGetWalletInfoCmd returns a new instance which can be used to issue a +// getwalletinfo JSON-RPC command. +func NewGetWalletInfoCmd() *GetWalletInfoCmd { + return &GetWalletInfoCmd{} +} + // ImportPrivKeyCmd defines the importprivkey JSON-RPC command. type ImportPrivKeyCmd struct { PrivKey string @@ -650,6 +659,7 @@ func init() { MustRegisterCmd("getreceivedbyaccount", (*GetReceivedByAccountCmd)(nil), flags) MustRegisterCmd("getreceivedbyaddress", (*GetReceivedByAddressCmd)(nil), flags) MustRegisterCmd("gettransaction", (*GetTransactionCmd)(nil), flags) + MustRegisterCmd("getwalletinfo", (*GetWalletInfoCmd)(nil), flags) MustRegisterCmd("importprivkey", (*ImportPrivKeyCmd)(nil), flags) MustRegisterCmd("keypoolrefill", (*KeyPoolRefillCmd)(nil), flags) MustRegisterCmd("listaccounts", (*ListAccountsCmd)(nil), flags) diff --git a/btcjson/walletsvrcmds_test.go b/btcjson/walletsvrcmds_test.go index ed551da8..d4755cc1 100644 --- a/btcjson/walletsvrcmds_test.go +++ b/btcjson/walletsvrcmds_test.go @@ -345,6 +345,17 @@ func TestWalletSvrCmds(t *testing.T) { IncludeWatchOnly: btcjson.Bool(true), }, }, + { + name: "getwalletinfo", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getwalletinfo") + }, + staticCmd: func() interface{} { + return btcjson.NewGetWalletInfoCmd() + }, + marshalled: `{"jsonrpc":"1.0","method":"getwalletinfo","params":[],"id":1}`, + unmarshalled: &btcjson.GetWalletInfoCmd{}, + }, { name: "importprivkey", newCmd: func() (interface{}, error) { From 51fca61707a0cfc4c935936aa5df02a6a56d95d5 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 26 Jul 2015 13:05:09 -0500 Subject: [PATCH 18/27] wire: Remove duplicate tx error path tests. --- wire/msgtx_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wire/msgtx_test.go b/wire/msgtx_test.go index aedc7a29..8ecc5067 100644 --- a/wire/msgtx_test.go +++ b/wire/msgtx_test.go @@ -329,8 +329,6 @@ func TestTxWireErrors(t *testing.T) { {multiTx, multiTxEncoded, pver, 4, io.ErrShortWrite, io.EOF}, // Force error in transaction input previous block hash. {multiTx, multiTxEncoded, pver, 5, io.ErrShortWrite, io.EOF}, - // Force error in transaction input previous block hash. - {multiTx, multiTxEncoded, pver, 5, io.ErrShortWrite, io.EOF}, // Force error in transaction input previous block output index. {multiTx, multiTxEncoded, pver, 37, io.ErrShortWrite, io.EOF}, // Force error in transaction input signature script length. @@ -474,8 +472,6 @@ func TestTxSerializeErrors(t *testing.T) { {multiTx, multiTxEncoded, 4, io.ErrShortWrite, io.EOF}, // Force error in transaction input previous block hash. {multiTx, multiTxEncoded, 5, io.ErrShortWrite, io.EOF}, - // Force error in transaction input previous block hash. - {multiTx, multiTxEncoded, 5, io.ErrShortWrite, io.EOF}, // Force error in transaction input previous block output index. {multiTx, multiTxEncoded, 37, io.ErrShortWrite, io.EOF}, // Force error in transaction input signature script length. From f8167ab36f9987403de53c6997dcbc170a841f84 Mon Sep 17 00:00:00 2001 From: Jonathan Gillham Date: Tue, 28 Jul 2015 11:31:43 +0100 Subject: [PATCH 19/27] txscript: Remove unneeded signature hash copies These copies were likely left over from when MsgTx had no deep copy functionality. --- txscript/script.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/txscript/script.go b/txscript/script.go index 333774c6..a811680a 100644 --- a/txscript/script.go +++ b/txscript/script.go @@ -300,9 +300,6 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.Msg // inputs that are not currently being processed. txCopy := tx.Copy() for i := range txCopy.TxIn { - var txIn wire.TxIn - txIn = *txCopy.TxIn[i] - txCopy.TxIn[i] = &txIn if i == idx { // UnparseScript cannot fail here because removeOpcode // above only returns a valid script. @@ -313,13 +310,6 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.Msg } } - // Default behavior has all outputs set up. - for i := range txCopy.TxOut { - var txOut wire.TxOut - txOut = *txCopy.TxOut[i] - txCopy.TxOut[i] = &txOut - } - switch hashType & sigHashMask { case SigHashNone: txCopy.TxOut = txCopy.TxOut[0:0] // Empty slice. From f891391f7cb697f1023a948feb67b6c3c88ede08 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 28 Jul 2015 03:59:37 -0500 Subject: [PATCH 20/27] peer: Optimize merkle block handling. This commit updates the merkle block handling to for the latest changes to the btcutil API and optimizes it along the way. Previously, the code was inefficiently reloading the transactions for the matched hashes from the database instead of simply pulling them from the full block that was used to create the merkle block. --- peer.go | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/peer.go b/peer.go index 68b782e9..ff430e0e 100644 --- a/peer.go +++ b/peer.go @@ -604,28 +604,8 @@ func (p *peer) pushMerkleBlockMsg(sha *wire.ShaHash, doneChan, waitChan chan str } // Generate a merkle block by filtering the requested block according - // to the filter for the peer and fetch any matched transactions from - // the database. - merkle, matchedHashes := bloom.NewMerkleBlock(blk, p.filter) - txList := p.server.db.FetchTxByShaList(matchedHashes) - - // Warn on any missing transactions which should not happen since the - // matched transactions come from an existing block. Also, find the - // final valid transaction index for later. - finalValidTxIndex := -1 - for i, txR := range txList { - if txR.Err != nil || txR.Tx == nil { - warnMsg := fmt.Sprintf("Failed to fetch transaction "+ - "%v which was matched by merkle block %v", - txR.Sha, sha) - if txR.Err != nil { - warnMsg += ": " + err.Error() - } - peerLog.Warnf(warnMsg) - continue - } - finalValidTxIndex = i - } + // to the filter for the peer. + merkle, matchedTxIndices := bloom.NewMerkleBlock(blk, p.filter) // Once we have fetched data wait for any previous operation to finish. if waitChan != nil { @@ -635,20 +615,21 @@ func (p *peer) pushMerkleBlockMsg(sha *wire.ShaHash, doneChan, waitChan chan str // Send the merkleblock. Only send the done channel with this message // if no transactions will be sent afterwards. var dc chan struct{} - if finalValidTxIndex == -1 { + if len(matchedTxIndices) == 0 { dc = doneChan } p.QueueMessage(merkle, dc) // Finally, send any matched transactions. - for i, txR := range txList { + blkTransactions := blk.MsgBlock().Transactions + for i, txIndex := range matchedTxIndices { // Only send the done channel on the final transaction. var dc chan struct{} - if i == finalValidTxIndex { + if i == len(matchedTxIndices)-1 { dc = doneChan } - if txR.Err == nil && txR.Tx != nil { - p.QueueMessage(txR.Tx, dc) + if txIndex < uint32(len(blkTransactions)) { + p.QueueMessage(blkTransactions[txIndex], dc) } } From 506fc9fb948801a768425b37d61b4441e1b58c47 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 28 Jul 2015 14:55:35 -0500 Subject: [PATCH 21/27] rpcserver: Allow tx result creation without block. This commit modifies the createTxRawResult code path along with callers to work with block headers as opposed to btcutil.Blocks. This in turn allows the code in handleGetRawTransaction and handleSearchRawTransactions to perform a much cheaper block header load as opposed to a full block load. While here, also very slightly optimize the createVinList function to avoid creating a util.Tx wrapper and to take advantage of the btcutil.Amount type added after the function was originally written --- rpcserver.go | 71 +++++++++++++++++++++++-------------------------- rpcwebsocket.go | 4 +-- 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index 1672ee20..46a901a6 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -615,10 +615,9 @@ func handleDebugLevel(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) // createVinList returns a slice of JSON objects for the inputs of the passed // transaction. func createVinList(mtx *wire.MsgTx) []btcjson.Vin { - tx := btcutil.NewTx(mtx) vinList := make([]btcjson.Vin, len(mtx.TxIn)) for i, v := range mtx.TxIn { - if blockchain.IsCoinBase(tx) { + if blockchain.IsCoinBaseTx(mtx) { vinList[i].Coinbase = hex.EncodeToString(v.SignatureScript) } else { vinList[i].Txid = v.PreviousOutPoint.Hash.String() @@ -644,7 +643,7 @@ func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params) []btcjson.Vou voutList := make([]btcjson.Vout, len(mtx.TxOut)) for i, v := range mtx.TxOut { voutList[i].N = uint32(i) - voutList[i].Value = float64(v.Value) / btcutil.SatoshiPerBitcoin + voutList[i].Value = btcutil.Amount(v.Value).ToBTC() // The disassembled string will contain [error] inline if the // script doesn't fully parse, so ignore the error here. @@ -675,9 +674,9 @@ func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params) []btcjson.Vou // createTxRawResult converts the passed transaction and associated parameters // to a raw transaction JSON object. -func createTxRawResult(chainParams *chaincfg.Params, txHash string, - mtx *wire.MsgTx, blk *btcutil.Block, maxIdx int64, - blkHash *wire.ShaHash) (*btcjson.TxRawResult, error) { +func createTxRawResult(chainParams *chaincfg.Params, mtx *wire.MsgTx, + txHash string, blkHeader *wire.BlockHeader, blkHash string, + blkHeight int64, chainHeight int64) (*btcjson.TxRawResult, error) { mtxHex, err := messageToHex(mtx) if err != nil { @@ -693,15 +692,12 @@ func createTxRawResult(chainParams *chaincfg.Params, txHash string, LockTime: mtx.LockTime, } - if blk != nil { - blockHeader := &blk.MsgBlock().Header - idx := blk.Height() - + if blkHeader != nil { // This is not a typo, they are identical in bitcoind as well. - txReply.Time = blockHeader.Timestamp.Unix() - txReply.Blocktime = blockHeader.Timestamp.Unix() - txReply.BlockHash = blkHash.String() - txReply.Confirmations = uint64(1 + maxIdx - idx) + txReply.Time = blkHeader.Timestamp.Unix() + txReply.Blocktime = blkHeader.Timestamp.Unix() + txReply.BlockHash = blkHash + txReply.Confirmations = uint64(1 + chainHeight - blkHeight) } return txReply, nil @@ -1035,11 +1031,9 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i txns := blk.Transactions() rawTxns := make([]btcjson.TxRawResult, len(txns)) for i, tx := range txns { - txHash := tx.Sha().String() - mtx := tx.MsgTx() - rawTxn, err := createTxRawResult(s.server.chainParams, - txHash, mtx, blk, maxIdx, sha) + tx.MsgTx(), tx.Sha().String(), blockHeader, + sha.String(), idx, maxIdx) if err != nil { return nil, err } @@ -2258,6 +2252,7 @@ func handleGetRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan str // try the block database. var mtx *wire.MsgTx var blkHash *wire.ShaHash + var blkHeight int64 tx, err := s.server.txMemPool.FetchTransaction(txHash) if err != nil { txList, err := s.server.db.FetchTxBySha(txHash) @@ -2268,10 +2263,10 @@ func handleGetRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan str } } - lastTx := len(txList) - 1 - mtx = txList[lastTx].Tx - - blkHash = txList[lastTx].BlkSha + lastTx := txList[len(txList)-1] + mtx = lastTx.Tx + blkHash = lastTx.BlkSha + blkHeight = lastTx.Height } else { mtx = tx.MsgTx() } @@ -2290,10 +2285,11 @@ func handleGetRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan str return mtxHex, nil } - var blk *btcutil.Block - var maxIdx int64 + var blkHeader *wire.BlockHeader + var blkHashStr string + var chainHeight int64 if blkHash != nil { - blk, err = s.server.db.FetchBlockBySha(blkHash) + blkHeader, err = s.server.db.FetchBlockHeaderBySha(blkHash) if err != nil { rpcsLog.Errorf("Error fetching sha: %v", err) return nil, &btcjson.RPCError{ @@ -2302,15 +2298,17 @@ func handleGetRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan str } } - _, maxIdx, err = s.server.db.NewestSha() + _, chainHeight, err = s.server.db.NewestSha() if err != nil { context := "Failed to get newest hash" return nil, internalRPCError(err.Error(), context) } + + blkHashStr = blkHash.String() } - rawTxn, err := createTxRawResult(s.server.chainParams, c.Txid, mtx, blk, - maxIdx, blkHash) + rawTxn, err := createTxRawResult(s.server.chainParams, mtx, + txHash.String(), blkHeader, blkHashStr, blkHeight, chainHeight) if err != nil { return nil, err } @@ -2946,9 +2944,11 @@ func handleSearchRawTransactions(s *rpcServer, cmd interface{}, closeChan <-chan // within a block. So we conditionally fetch a txs // embedded block here. This will be reflected in the // final JSON output (mempool won't have confirmations). - var blk *btcutil.Block + var blkHeader *wire.BlockHeader + var blkHashStr string + var blkHeight int64 if txReply.BlkSha != nil { - blk, err = s.server.db.FetchBlockBySha(txReply.BlkSha) + blkHeader, err = s.server.db.FetchBlockHeaderBySha(txReply.BlkSha) if err != nil { rpcsLog.Errorf("Error fetching sha: %v", err) return nil, &btcjson.RPCError{ @@ -2956,15 +2956,12 @@ func handleSearchRawTransactions(s *rpcServer, cmd interface{}, closeChan <-chan Message: "Block not found", } } + blkHashStr = txReply.BlkSha.String() + blkHeight = txReply.Height } - var blkHash *wire.ShaHash - if blk != nil { - blkHash = blk.Sha() - } - - rawTxn, err := createTxRawResult(s.server.chainParams, - txHash, mtx, blk, maxIdx, blkHash) + rawTxn, err := createTxRawResult(s.server.chainParams, mtx, + txHash, blkHeader, blkHashStr, blkHeight, maxIdx) if err != nil { return nil, err } diff --git a/rpcwebsocket.go b/rpcwebsocket.go index 5b2ec323..86f508bb 100644 --- a/rpcwebsocket.go +++ b/rpcwebsocket.go @@ -487,8 +487,8 @@ func (m *wsNotificationManager) notifyForNewTx(clients map[chan struct{}]*wsClie } net := m.server.server.chainParams - rawTx, err := createTxRawResult(net, txShaStr, mtx, nil, - 0, nil) + rawTx, err := createTxRawResult(net, mtx, txShaStr, nil, + "", 0, 0) if err != nil { return } From 2dc868772839cb3af472d811c784b304e22aab19 Mon Sep 17 00:00:00 2001 From: Daniel Krawisz Date: Sun, 31 May 2015 16:47:58 -0500 Subject: [PATCH 22/27] Fix incorrect ip connection attempt logic. The comment says "only allow recent nodes (10mins) after we failed 30 times", but the server actually did the opposite and allowed only recent nodes before 30 failed connection attempts. This corrects the server's behavior. --- server.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server.go b/server.go index 474efca0..1d8aaa59 100644 --- a/server.go +++ b/server.go @@ -769,8 +769,7 @@ out: // only allow recent nodes (10mins) after we failed 30 // times - if time.Now().After(addr.LastAttempt().Add(10*time.Minute)) && - tries < 30 { + if tries < 30 && time.Now().Sub(addr.LastAttempt()) < 10*time.Minute { continue } From 88b15e74f0a1373c621c314d7b5db59323194c48 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 27 Jul 2015 16:57:45 -0500 Subject: [PATCH 23/27] docs: Add info describing model commit messages. --- docs/code_contribution_guidelines.md | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/code_contribution_guidelines.md b/docs/code_contribution_guidelines.md index 0de7c317..769842df 100644 --- a/docs/code_contribution_guidelines.md +++ b/docs/code_contribution_guidelines.md @@ -6,6 +6,7 @@ 4.1. [Share Early, Share Often](#ShareEarly)
4.2. [Testing](#Testing)
4.3. [Code Documentation and Commenting](#CodeDocumentation)
+4.4. [Model Git Commit Messages](#ModelGitCommitMessages)
5. [Code Approval Process](#CodeApproval)
5.1 [Code Review](#CodeReview)
5.2 [Rework Code (if needed)](#CodeRework)
@@ -194,6 +195,52 @@ if amt < 5460 { but it was left as a magic number to show how much of a difference a good comment can make. +
+### 4.4 Code Documentation and Commenting + +This project prefers to keep a clean commit history with well-formed commit +messages. This section illustrates a model commit message and provides a bit +of background for it. This content was originally created by Tim Pope and made +available on his website, however that website is no longer active, so it is +being provided here. + +Here’s a model Git commit message: + +``` +Short (50 chars or less) summary of changes + +More detailed explanatory text, if necessary. Wrap it to about 72 +characters or so. In some contexts, the first line is treated as the +subject of an email and the rest of the text as the body. The blank +line separating the summary from the body is critical (unless you omit +the body entirely); tools like rebase can get confused if you run the +two together. + +Write your commit message in the present tense: "Fix bug" and not "Fixed +bug." This convention matches up with commit messages generated by +commands like git merge and git revert. + +Further paragraphs come after blank lines. + +- Bullet points are okay, too +- Typically a hyphen or asterisk is used for the bullet, preceded by a + single space, with blank lines in between, but conventions vary here +- Use a hanging indent +``` + +Here are some of the reasons why wrapping your commit messages to 72 columns is +a good thing. + +- git log doesn’t do any special special wrapping of the commit messages. With + the default pager of less -S, this means your paragraphs flow far off the edge + of the screen, making them difficult to read. On an 80 column terminal, if we + subtract 4 columns for the indent on the left and 4 more for symmetry on the + right, we’re left with 72 columns. +- git format-patch --stdout converts a series of commits to a series of emails, + using the messages for the message body. Good email netiquette dictates we + wrap our plain text emails such that there’s room for a few levels of nested + reply indicators without overflow in an 80 column terminal. + ### 5. Code Approval Process From b448a2b6bc717fd1afc8b7bf47e984fd4c49070c Mon Sep 17 00:00:00 2001 From: Jonathan Gillham Date: Sun, 2 Aug 2015 22:21:27 +0100 Subject: [PATCH 24/27] Make PubKey variable names consistent. --- rpcwebsocket.go | 16 ++++++++-------- txscript/error.go | 4 ++-- txscript/opcode.go | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rpcwebsocket.go b/rpcwebsocket.go index 86f508bb..3c1781fc 100644 --- a/rpcwebsocket.go +++ b/rpcwebsocket.go @@ -1596,8 +1596,8 @@ type rescanKeys struct { fallbacks map[string]struct{} pubKeyHashes map[[ripemd160.Size]byte]struct{} scriptHashes map[[ripemd160.Size]byte]struct{} - compressedPubkeys map[[33]byte]struct{} - uncompressedPubkeys map[[65]byte]struct{} + compressedPubKeys map[[33]byte]struct{} + uncompressedPubKeys map[[65]byte]struct{} unspent map[wire.OutPoint]struct{} } @@ -1684,14 +1684,14 @@ func rescanBlock(wsc *wsClient, lookups *rescanKeys, blk *btcutil.Block) { case 33: // Compressed var key [33]byte copy(key[:], sa) - if _, ok := lookups.compressedPubkeys[key]; ok { + if _, ok := lookups.compressedPubKeys[key]; ok { found = true } case 65: // Uncompressed var key [65]byte copy(key[:], sa) - if _, ok := lookups.uncompressedPubkeys[key]; ok { + if _, ok := lookups.uncompressedPubKeys[key]; ok { found = true } @@ -1839,8 +1839,8 @@ func handleRescan(wsc *wsClient, icmd interface{}) (interface{}, error) { fallbacks: map[string]struct{}{}, pubKeyHashes: map[[ripemd160.Size]byte]struct{}{}, scriptHashes: map[[ripemd160.Size]byte]struct{}{}, - compressedPubkeys: map[[33]byte]struct{}{}, - uncompressedPubkeys: map[[65]byte]struct{}{}, + compressedPubKeys: map[[33]byte]struct{}{}, + uncompressedPubKeys: map[[65]byte]struct{}{}, unspent: map[wire.OutPoint]struct{}{}, } var compressedPubkey [33]byte @@ -1867,11 +1867,11 @@ func handleRescan(wsc *wsClient, icmd interface{}) (interface{}, error) { switch len(pubkeyBytes) { case 33: // Compressed copy(compressedPubkey[:], pubkeyBytes) - lookups.compressedPubkeys[compressedPubkey] = struct{}{} + lookups.compressedPubKeys[compressedPubkey] = struct{}{} case 65: // Uncompressed copy(uncompressedPubkey[:], pubkeyBytes) - lookups.uncompressedPubkeys[uncompressedPubkey] = struct{}{} + lookups.uncompressedPubKeys[uncompressedPubkey] = struct{}{} default: jsonErr := btcjson.RPCError{ diff --git a/txscript/error.go b/txscript/error.go index 346a418e..f9a806dd 100644 --- a/txscript/error.go +++ b/txscript/error.go @@ -58,9 +58,9 @@ var ( // without and OP_ENDIF to correspond to a conditional expression. ErrStackMissingEndif = fmt.Errorf("execute fail, in conditional execution") - // ErrStackTooManyPubkeys is returned if an OP_CHECKMULTISIG is + // ErrStackTooManyPubKeys is returned if an OP_CHECKMULTISIG is // encountered with more than MaxPubKeysPerMultiSig pubkeys present. - ErrStackTooManyPubkeys = errors.New("Invalid pubkey count in OP_CHECKMULTISIG") + ErrStackTooManyPubKeys = errors.New("Invalid pubkey count in OP_CHECKMULTISIG") // ErrStackTooManyOperations is returned if a script has more than // MaxOpsPerScript opcodes that do not push data. diff --git a/txscript/opcode.go b/txscript/opcode.go index a5a8d213..2c31098f 100644 --- a/txscript/opcode.go +++ b/txscript/opcode.go @@ -1904,7 +1904,7 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { numPubKeys := int(numKeys.Int32()) if numPubKeys < 0 || numPubKeys > MaxPubKeysPerMultiSig { - return ErrStackTooManyPubkeys + return ErrStackTooManyPubKeys } vm.numOps += numPubKeys if vm.numOps > MaxOpsPerScript { From 3331d6098ba6b1605bfdaaa2de1becfc77e94d74 Mon Sep 17 00:00:00 2001 From: David Hill Date: Sat, 1 Aug 2015 10:43:06 -0400 Subject: [PATCH 25/27] txscript: New function IsUnspendable IsUnspendable takes a public key script and returns whether it is spendable. Additionally, hook this into the mempool isDust function, since unspendable outputs can't be spent. This mimics Bitcoin Core commit 0aad1f13b2430165062bf9436036c1222a8724da --- mempool.go | 5 +++++ txscript/script.go | 12 ++++++++++++ txscript/script_test.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/mempool.go b/mempool.go index ebcaf5f7..360ff80f 100644 --- a/mempool.go +++ b/mempool.go @@ -107,6 +107,11 @@ type txMemPool struct { // relay fee. In particular, if the cost to the network to spend coins is more // than 1/3 of the minimum transaction relay fee, it is considered dust. func isDust(txOut *wire.TxOut) bool { + // Unspendable outputs are considered dust. + if txscript.IsUnspendable(txOut.PkScript) { + return true + } + // The total serialized size consists of the output and the associated // input script to redeem it. Since there is no input script // to redeem it yet, use the minimum size of a typical input script. diff --git a/txscript/script.go b/txscript/script.go index a811680a..a9c74939 100644 --- a/txscript/script.go +++ b/txscript/script.go @@ -458,3 +458,15 @@ func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) int { shPops, _ := parseScript(shScript) return getSigOpCount(shPops, true) } + +// IsUnspendable returns whether the passed public key script is unspendable, or +// guaranteed to fail at execution. This allows inputs to be pruned instantly +// when entering the UTXO set. +func IsUnspendable(pkScript []byte) bool { + pops, err := parseScript(pkScript) + if err != nil { + return true + } + + return len(pops) > 0 && pops[0].opcode.value == OP_RETURN +} diff --git a/txscript/script_test.go b/txscript/script_test.go index 21b88af7..012d07f8 100644 --- a/txscript/script_test.go +++ b/txscript/script_test.go @@ -486,3 +486,38 @@ func TestIsPushOnlyScript(t *testing.T) { "%v", test.name, true, test.expected) } } + +// TestIsUnspendable ensures the IsUnspendable function returns the expected +// results. +func TestIsUnspendable(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + pkScript []byte + expected bool + }{ + { + // Unspendable + pkScript: []byte{0x6a, 0x04, 0x74, 0x65, 0x73, 0x74}, + expected: true, + }, + { + // Spendable + pkScript: []byte{0x76, 0xa9, 0x14, 0x29, 0x95, 0xa0, + 0xfe, 0x68, 0x43, 0xfa, 0x9b, 0x95, 0x45, + 0x97, 0xf0, 0xdc, 0xa7, 0xa4, 0x4d, 0xf6, + 0xfa, 0x0b, 0x5c, 0x88, 0xac}, + expected: false, + }, + } + + for i, test := range tests { + res := txscript.IsUnspendable(test.pkScript) + if res != test.expected { + t.Errorf("TestIsUnspendable #%d failed: got %v want %v", + i, res, test.expected) + continue + } + } +} From 27f7f8235518af9c7f1bdc99db0cf81d2a9a1a3d Mon Sep 17 00:00:00 2001 From: Jonathan Gillham Date: Sun, 9 Aug 2015 14:06:36 +0100 Subject: [PATCH 26/27] txscript: Make error strings idiomatic. --- txscript/error.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/txscript/error.go b/txscript/error.go index f9a806dd..17cc93fd 100644 --- a/txscript/error.go +++ b/txscript/error.go @@ -28,11 +28,11 @@ var ( // ErrStackOpDisabled is returned when a disabled opcode is encountered // in the script. - ErrStackOpDisabled = errors.New("Disabled Opcode") + ErrStackOpDisabled = errors.New("disabled opcode") // ErrStackVerifyFailed is returned when one of the OP_VERIFY or // OP_*VERIFY instructions is executed and the conditions fails. - ErrStackVerifyFailed = errors.New("Verify failed") + ErrStackVerifyFailed = errors.New("verify failed") // ErrStackNumberTooBig is returned when the argument for an opcode that // should be an offset is obviously far too large. @@ -40,15 +40,15 @@ var ( // ErrStackInvalidOpcode is returned when an opcode marked as invalid or // a completely undefined opcode is encountered. - ErrStackInvalidOpcode = errors.New("Invalid Opcode") + ErrStackInvalidOpcode = errors.New("invalid opcode") // ErrStackReservedOpcode is returned when an opcode marked as reserved // is encountered. - ErrStackReservedOpcode = errors.New("Reserved Opcode") + ErrStackReservedOpcode = errors.New("reserved opcode") // ErrStackEarlyReturn is returned when OP_RETURN is executed in the // script. - ErrStackEarlyReturn = errors.New("Script returned early") + ErrStackEarlyReturn = errors.New("script returned early") // ErrStackNoIf is returned if an OP_ELSE or OP_ENDIF is encountered // without first having an OP_IF or OP_NOTIF in the script. @@ -60,15 +60,15 @@ var ( // ErrStackTooManyPubKeys is returned if an OP_CHECKMULTISIG is // encountered with more than MaxPubKeysPerMultiSig pubkeys present. - ErrStackTooManyPubKeys = errors.New("Invalid pubkey count in OP_CHECKMULTISIG") + ErrStackTooManyPubKeys = errors.New("invalid pubkey count in OP_CHECKMULTISIG") // ErrStackTooManyOperations is returned if a script has more than // MaxOpsPerScript opcodes that do not push data. - ErrStackTooManyOperations = errors.New("Too many operations in script") + ErrStackTooManyOperations = errors.New("too many operations in script") // ErrStackElementTooBig is returned if the size of an element to be // pushed to the stack is over MaxScriptElementSize. - ErrStackElementTooBig = errors.New("Element in script too large") + ErrStackElementTooBig = errors.New("element in script too large") // ErrStackUnknownAddress is returned when ScriptToAddrHash does not // recognise the pattern of the script and thus can not find the address @@ -82,12 +82,12 @@ var ( // ErrStackScriptUnfinished is returned when CheckErrorCondition is // called on a script that has not finished executing. - ErrStackScriptUnfinished = errors.New("Error check when script unfinished") + ErrStackScriptUnfinished = errors.New("error check when script unfinished") // ErrStackEmptyStack is returned when the stack is empty at the end of // execution. Normal operation requires that a boolean is on top of the // stack when the scripts have finished executing. - ErrStackEmptyStack = errors.New("Stack empty at end of execution") + ErrStackEmptyStack = errors.New("stack empty at end of execution") // ErrStackP2SHNonPushOnly is returned when a Pay-to-Script-Hash // transaction is encountered and the ScriptSig does operations other @@ -105,7 +105,7 @@ var ( // ErrStackInvalidIndex is returned when an out-of-bounds index was // passed to a function. - ErrStackInvalidIndex = errors.New("Invalid script index") + ErrStackInvalidIndex = errors.New("invalid script index") // ErrStackNonPushOnly is returned when ScriptInfo is called with a // pkScript that peforms operations other that pushing data to the stack. @@ -113,7 +113,7 @@ var ( // ErrStackOverflow is returned when stack and altstack combined depth // is over the limit. - ErrStackOverflow = errors.New("Stacks overflowed") + ErrStackOverflow = errors.New("stack overflow") // ErrStackInvalidLowSSignature is returned when the ScriptVerifyLowS // flag is set and the script contains any signatures whose S values From 0280fa0264f907cc9a8113f40cec0327206e0196 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 7 Aug 2015 21:20:49 -0500 Subject: [PATCH 27/27] Convert block heights to int32. This commit converts all block height references to int32 instead of int64. The current target block production rate is 10 mins per block which means it will take roughly 40,800 years to reach the maximum height an int32 affords. Even if the target rate were lowered to one block per minute, it would still take roughly another 4,080 years to reach the maximum. In the mean time, there is no reason to use a larger type which results in higher memory and disk space usage. However, for now, in order to avoid having to reserialize a bunch of database information, the heights are still serialized to the database as 8-byte uint64s. This is being mainly being done in preparation for further upcoming infrastructure changes which will use the smaller and more efficient 4-byte serialization in the database as well. --- blockchain/accept.go | 2 +- blockchain/blocklocator.go | 6 ++-- blockchain/chain.go | 14 ++++----- blockchain/checkpoints.go | 2 +- blockchain/common_test.go | 2 +- blockchain/difficulty.go | 4 +-- blockchain/internal_test.go | 2 +- blockchain/txlookup.go | 2 +- blockchain/validate.go | 18 ++++++------ blockchain/validate_test.go | 2 +- blockmanager.go | 14 ++++----- chaincfg/params.go | 2 +- chainindexer.go | 4 +-- cmd/dropafter/dropafter.go | 4 +-- cmd/findcheckpoint/findcheckpoint.go | 4 +-- cpuminer.go | 2 +- database/db.go | 18 ++++++------ database/interface_test.go | 16 +++++----- database/ldb/block.go | 44 ++++++++++++++-------------- database/ldb/dup_test.go | 2 +- database/ldb/insertremove_test.go | 2 +- database/ldb/leveldb.go | 16 +++++----- database/ldb/operational_test.go | 26 ++++++++-------- database/ldb/tx.go | 26 ++++++++-------- database/memdb/memdb.go | 32 ++++++++++---------- database/reorg_test.go | 10 +++---- mempool.go | 14 ++++----- mining.go | 12 ++++---- peer.go | 8 ++--- rpcserver.go | 38 ++++++++++++------------ rpcwebsocket.go | 6 ++-- 31 files changed, 177 insertions(+), 177 deletions(-) diff --git a/blockchain/accept.go b/blockchain/accept.go index c5b07d52..f5dd2842 100644 --- a/blockchain/accept.go +++ b/blockchain/accept.go @@ -30,7 +30,7 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) // The height of this block is one more than the referenced previous // block. - blockHeight := int64(0) + blockHeight := int32(0) if prevNode != nil { blockHeight = prevNode.height + 1 } diff --git a/blockchain/blocklocator.go b/blockchain/blocklocator.go index 7c9019bc..c05de0cf 100644 --- a/blockchain/blocklocator.go +++ b/blockchain/blocklocator.go @@ -48,8 +48,8 @@ func (b *BlockChain) BlockLocatorFromHash(hash *wire.ShaHash) BlockLocator { // Attempt to find the height of the block that corresponds to the // passed hash, and if it's on a side chain, also find the height at // which it forks from the main chain. - blockHeight := int64(-1) - forkHeight := int64(-1) + blockHeight := int32(-1) + forkHeight := int32(-1) node, exists := b.index[*hash] if !exists { // Try to look up the height for passed block hash. Assume an @@ -80,7 +80,7 @@ func (b *BlockChain) BlockLocatorFromHash(hash *wire.ShaHash) BlockLocator { // in the BlockLocator comment and make sure to leave room for the // final genesis hash. iterNode := node - increment := int64(1) + increment := int32(1) for len(locator) < wire.MaxBlockLocatorsPerMsg-1 { // Once there are 10 locators, exponentially increase the // distance between each block locator. diff --git a/blockchain/chain.go b/blockchain/chain.go index a602f1ec..dae879d7 100644 --- a/blockchain/chain.go +++ b/blockchain/chain.go @@ -58,7 +58,7 @@ type blockNode struct { parentHash *wire.ShaHash // height is the position in the block chain. - height int64 + height int32 // workSum is the total amount of work in the chain up to and including // this node. @@ -79,7 +79,7 @@ type blockNode struct { // completely disconnected from the chain and the workSum value is just the work // for the passed block. The work sum is updated accordingly when the node is // inserted into a chain. -func newBlockNode(blockHeader *wire.BlockHeader, blockSha *wire.ShaHash, height int64) *blockNode { +func newBlockNode(blockHeader *wire.BlockHeader, blockSha *wire.ShaHash, height int32) *blockNode { // Make a copy of the hash so the node doesn't keep a reference to part // of the full block/block header preventing it from being garbage // collected. @@ -144,7 +144,7 @@ func removeChildNode(children []*blockNode, node *blockNode) []*blockNode { type BlockChain struct { db database.Db chainParams *chaincfg.Params - checkpointsByHeight map[int64]*chaincfg.Checkpoint + checkpointsByHeight map[int32]*chaincfg.Checkpoint notifications NotificationCallback root *blockNode bestChain *blockNode @@ -384,7 +384,7 @@ func (b *BlockChain) GenerateInitialIndex() error { // Start at the next block after the latest one on the next loop // iteration. - start += int64(len(hashList)) + start += int32(len(hashList)) } return nil @@ -567,7 +567,7 @@ func (b *BlockChain) pruneBlockNodes() error { // the latter loads the node and the goal is to find nodes still in // memory that can be pruned. newRootNode := b.bestChain - for i := int64(0); i < minMemoryNodes-1 && newRootNode != nil; i++ { + for i := int32(0); i < minMemoryNodes-1 && newRootNode != nil; i++ { newRootNode = newRootNode.parent } @@ -1069,9 +1069,9 @@ func (b *BlockChain) IsCurrent(timeSource MedianTimeSource) bool { // interested in receiving notifications. func New(db database.Db, params *chaincfg.Params, c NotificationCallback) *BlockChain { // Generate a checkpoint by height map from the provided checkpoints. - var checkpointsByHeight map[int64]*chaincfg.Checkpoint + var checkpointsByHeight map[int32]*chaincfg.Checkpoint if len(params.Checkpoints) > 0 { - checkpointsByHeight = make(map[int64]*chaincfg.Checkpoint) + checkpointsByHeight = make(map[int32]*chaincfg.Checkpoint) for i := range params.Checkpoints { checkpoint := ¶ms.Checkpoints[i] checkpointsByHeight[checkpoint.Height] = checkpoint diff --git a/blockchain/checkpoints.go b/blockchain/checkpoints.go index d5840f11..c0dc21c2 100644 --- a/blockchain/checkpoints.go +++ b/blockchain/checkpoints.go @@ -59,7 +59,7 @@ func (b *BlockChain) LatestCheckpoint() *chaincfg.Checkpoint { // verifyCheckpoint returns whether the passed block height and hash combination // match the hard-coded checkpoint data. It also returns true if there is no // checkpoint data for the passed block height. -func (b *BlockChain) verifyCheckpoint(height int64, hash *wire.ShaHash) bool { +func (b *BlockChain) verifyCheckpoint(height int32, hash *wire.ShaHash) bool { if b.noCheckpoints || len(b.chainParams.Checkpoints) == 0 { return true } diff --git a/blockchain/common_test.go b/blockchain/common_test.go index 8a557570..8963f6f2 100644 --- a/blockchain/common_test.go +++ b/blockchain/common_test.go @@ -184,7 +184,7 @@ func loadTxStore(filename string) (blockchain.TxStore, error) { if err != nil { return nil, err } - txD.BlockHeight = int64(uintBuf) + txD.BlockHeight = int32(uintBuf) // Num spent bits. err = binary.Read(r, binary.LittleEndian, &uintBuf) diff --git a/blockchain/difficulty.go b/blockchain/difficulty.go index 0a045571..c922df9b 100644 --- a/blockchain/difficulty.go +++ b/blockchain/difficulty.go @@ -25,7 +25,7 @@ const ( // BlocksPerRetarget is the number of blocks between each difficulty // retarget. It is calculated based on the desired block generation // rate. - BlocksPerRetarget = int64(targetTimespan / targetSpacing) + BlocksPerRetarget = int32(targetTimespan / targetSpacing) // retargetAdjustmentFactor is the adjustment factor used to limit // the minimum and maximum amount of adjustment that can occur between @@ -295,7 +295,7 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim // Get the block node at the previous retarget (targetTimespan days // worth of blocks). firstNode := lastNode - for i := int64(0); i < BlocksPerRetarget-1 && firstNode != nil; i++ { + for i := int32(0); i < BlocksPerRetarget-1 && firstNode != nil; i++ { // Get the previous block node. This function is used over // simply accessing firstNode.parent directly as it will // dynamically create previous block nodes as needed. This diff --git a/blockchain/internal_test.go b/blockchain/internal_test.go index 87a9ba81..e31b03fd 100644 --- a/blockchain/internal_test.go +++ b/blockchain/internal_test.go @@ -19,7 +19,7 @@ import ( // TstSetCoinbaseMaturity makes the ability to set the coinbase maturity // available to the test package. -func TstSetCoinbaseMaturity(maturity int64) { +func TstSetCoinbaseMaturity(maturity int32) { coinbaseMaturity = maturity } diff --git a/blockchain/txlookup.go b/blockchain/txlookup.go index 689f0d25..b7c8fe65 100644 --- a/blockchain/txlookup.go +++ b/blockchain/txlookup.go @@ -17,7 +17,7 @@ import ( type TxData struct { Tx *btcutil.Tx Hash *wire.ShaHash - BlockHeight int64 + BlockHeight int32 Spent []bool Err error } diff --git a/blockchain/validate.go b/blockchain/validate.go index 0fc9a949..fc00be45 100644 --- a/blockchain/validate.go +++ b/blockchain/validate.go @@ -55,7 +55,7 @@ var ( // coinbaseMaturity is the internal variable used for validating the // spending of coinbase outputs. A variable rather than the exported // constant is used because the tests need the ability to modify it. - coinbaseMaturity = int64(CoinbaseMaturity) + coinbaseMaturity = int32(CoinbaseMaturity) // zeroHash is the zero value for a wire.ShaHash and is defined as // a package level variable to avoid the need to create a new instance @@ -128,7 +128,7 @@ func IsCoinBase(tx *btcutil.Tx) bool { } // IsFinalizedTransaction determines whether or not a transaction is finalized. -func IsFinalizedTransaction(tx *btcutil.Tx, blockHeight int64, blockTime time.Time) bool { +func IsFinalizedTransaction(tx *btcutil.Tx, blockHeight int32, blockTime time.Time) bool { msgTx := tx.MsgTx() // Lock time of zero means the transaction is finalized. @@ -143,7 +143,7 @@ func IsFinalizedTransaction(tx *btcutil.Tx, blockHeight int64, blockTime time.Ti // threshold it is a block height. blockTimeOrHeight := int64(0) if lockTime < txscript.LockTimeThreshold { - blockTimeOrHeight = blockHeight + blockTimeOrHeight = int64(blockHeight) } else { blockTimeOrHeight = blockTime.Unix() } @@ -187,13 +187,13 @@ func isBIP0030Node(node *blockNode) bool { // // At the target block generation rate for the main network, this is // approximately every 4 years. -func CalcBlockSubsidy(height int64, chainParams *chaincfg.Params) int64 { +func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 { if chainParams.SubsidyHalvingInterval == 0 { return baseSubsidy } // Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval) - return baseSubsidy >> uint(height/int64(chainParams.SubsidyHalvingInterval)) + return baseSubsidy >> uint(height/chainParams.SubsidyHalvingInterval) } // CheckTransactionSanity performs some preliminary checks on a transaction to @@ -738,7 +738,7 @@ func (b *BlockChain) checkBlockContext(block *btcutil.Block, prevNode *blockNode // ExtractCoinbaseHeight attempts to extract the height of the block from the // scriptSig of a coinbase transaction. Coinbase heights are only present in // blocks of version 2 or later. This was added as part of BIP0034. -func ExtractCoinbaseHeight(coinbaseTx *btcutil.Tx) (int64, error) { +func ExtractCoinbaseHeight(coinbaseTx *btcutil.Tx) (int32, error) { sigScript := coinbaseTx.MsgTx().TxIn[0].SignatureScript if len(sigScript) < 1 { str := "the coinbase signature script for blocks of " + @@ -761,12 +761,12 @@ func ExtractCoinbaseHeight(coinbaseTx *btcutil.Tx) (int64, error) { copy(serializedHeightBytes, sigScript[1:serializedLen+1]) serializedHeight := binary.LittleEndian.Uint64(serializedHeightBytes) - return int64(serializedHeight), nil + return int32(serializedHeight), nil } // checkSerializedHeight checks if the signature script in the passed // transaction starts with the serialized block height of wantHeight. -func checkSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int64) error { +func checkSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int32) error { serializedHeight, err := ExtractCoinbaseHeight(coinbaseTx) if err != nil { return err @@ -849,7 +849,7 @@ func (b *BlockChain) checkBIP0030(node *blockNode, block *btcutil.Block) error { // amount, and verifying the signatures to prove the spender was the owner of // the bitcoins and therefore allowed to spend them. As it checks the inputs, // it also calculates the total fees for the transaction and returns that value. -func CheckTransactionInputs(tx *btcutil.Tx, txHeight int64, txStore TxStore) (int64, error) { +func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, txStore TxStore) (int64, error) { // Coinbase transactions have no inputs. if IsCoinBase(tx) { return 0, nil diff --git a/blockchain/validate_test.go b/blockchain/validate_test.go index 2589f1ca..cca4470e 100644 --- a/blockchain/validate_test.go +++ b/blockchain/validate_test.go @@ -82,7 +82,7 @@ func TestCheckSerializedHeight(t *testing.T) { tests := []struct { sigScript []byte // Serialized data - wantHeight int64 // Expected height + wantHeight int32 // Expected height err error // Expected error type }{ // No serialized height length. diff --git a/blockmanager.go b/blockmanager.go index 1fb90538..68d01610 100644 --- a/blockmanager.go +++ b/blockmanager.go @@ -150,7 +150,7 @@ type pauseMsg struct { // headerNode is used as a node in a list of headers that are linked together // between checkpoints. type headerNode struct { - height int64 + height int32 sha *wire.ShaHash } @@ -163,7 +163,7 @@ type headerNode struct { type chainState struct { sync.Mutex newestHash *wire.ShaHash - newestHeight int64 + newestHeight int32 pastMedianTime time.Time pastMedianTimeErr error } @@ -172,7 +172,7 @@ type chainState struct { // chain. // // This function is safe for concurrent access. -func (c *chainState) Best() (*wire.ShaHash, int64) { +func (c *chainState) Best() (*wire.ShaHash, int32) { c.Lock() defer c.Unlock() @@ -207,7 +207,7 @@ type blockManager struct { // resetHeaderState sets the headers-first mode state to values appropriate for // syncing from a new peer. -func (b *blockManager) resetHeaderState(newestHash *wire.ShaHash, newestHeight int64) { +func (b *blockManager) resetHeaderState(newestHash *wire.ShaHash, newestHeight int32) { b.headersFirstMode = false b.headerList.Init() b.startHeader = nil @@ -225,7 +225,7 @@ func (b *blockManager) resetHeaderState(newestHash *wire.ShaHash, newestHeight i // This allows fast access to chain information since btcchain is currently not // safe for concurrent access and the block manager is typically quite busy // processing block and inventory. -func (b *blockManager) updateChainState(newestHash *wire.ShaHash, newestHeight int64) { +func (b *blockManager) updateChainState(newestHash *wire.ShaHash, newestHeight int32) { b.chainState.Lock() defer b.chainState.Unlock() @@ -243,7 +243,7 @@ func (b *blockManager) updateChainState(newestHash *wire.ShaHash, newestHeight i // It returns nil when there is not one either because the height is already // later than the final checkpoint or some other reason such as disabled // checkpoints. -func (b *blockManager) findNextHeaderCheckpoint(height int64) *chaincfg.Checkpoint { +func (b *blockManager) findNextHeaderCheckpoint(height int32) *chaincfg.Checkpoint { // There is no next checkpoint if checkpoints are disabled or there are // none for this current network. if cfg.DisableCheckpoints { @@ -524,7 +524,7 @@ func (b *blockManager) current() bool { // TODO(oga) we can get chain to return the height of each block when we // parse an orphan, which would allow us to update the height of peers // from what it was at initial handshake. - if err != nil || height < int64(b.syncPeer.lastBlock) { + if err != nil || height < b.syncPeer.lastBlock { return false } return true diff --git a/chaincfg/params.go b/chaincfg/params.go index 053c1b2a..875dbde4 100644 --- a/chaincfg/params.go +++ b/chaincfg/params.go @@ -44,7 +44,7 @@ var ( // documentation for blockchain.IsCheckpointCandidate for details on the // selection criteria. type Checkpoint struct { - Height int64 + Height int32 Hash *wire.ShaHash } diff --git a/chainindexer.go b/chainindexer.go index fd9000e9..d33dee44 100644 --- a/chainindexer.go +++ b/chainindexer.go @@ -69,8 +69,8 @@ type addrIndexer struct { addrIndexJobs chan *indexBlockMsg writeRequests chan *writeIndexReq progressLogger *blockProgressLogger - currentIndexTip int64 - chainTip int64 + currentIndexTip int32 + chainTip int32 sync.Mutex } diff --git a/cmd/dropafter/dropafter.go b/cmd/dropafter/dropafter.go index dca1041e..b29247c2 100644 --- a/cmd/dropafter/dropafter.go +++ b/cmd/dropafter/dropafter.go @@ -167,7 +167,7 @@ var errBadShaPrefix = errors.New("invalid prefix") var errBadShaLen = errors.New("invalid len") var errBadShaChar = errors.New("invalid character") -func parsesha(argstr string) (argtype int, height int64, psha *wire.ShaHash, err error) { +func parsesha(argstr string) (argtype int, height int32, psha *wire.ShaHash, err error) { var sha wire.ShaHash var hashbuf string @@ -189,7 +189,7 @@ func parsesha(argstr string) (argtype int, height int64, psha *wire.ShaHash, err var h int h, err = strconv.Atoi(argstr) if err == nil { - height = int64(h) + height = int32(h) return } log.Infof("Unable to parse height %v, err %v", height, err) diff --git a/cmd/findcheckpoint/findcheckpoint.go b/cmd/findcheckpoint/findcheckpoint.go index d7ef81e6..a2d446b8 100644 --- a/cmd/findcheckpoint/findcheckpoint.go +++ b/cmd/findcheckpoint/findcheckpoint.go @@ -61,7 +61,7 @@ func findCandidates(db database.Db, latestHash *wire.ShaHash) ([]*chaincfg.Check // The latest known block must be at least the last known checkpoint // plus required checkpoint confirmations. - checkpointConfirmations := int64(blockchain.CheckpointConfirmations) + checkpointConfirmations := int32(blockchain.CheckpointConfirmations) requiredHeight := latestCheckpoint.Height + checkpointConfirmations if block.Height() < requiredHeight { return nil, fmt.Errorf("the block database is only at height "+ @@ -79,7 +79,7 @@ func findCandidates(db database.Db, latestHash *wire.ShaHash) ([]*chaincfg.Check // Loop backwards through the chain to find checkpoint candidates. candidates := make([]*chaincfg.Checkpoint, 0, cfg.NumCandidates) - numTested := int64(0) + numTested := int32(0) for len(candidates) < cfg.NumCandidates && block.Height() > requiredHeight { // Display progress. if numTested%progressInterval == 0 { diff --git a/cpuminer.go b/cpuminer.go index eaba26cd..f8e54afb 100644 --- a/cpuminer.go +++ b/cpuminer.go @@ -165,7 +165,7 @@ func (m *CPUMiner) submitBlock(block *btcutil.Block) bool { // This function will return early with false when conditions that trigger a // stale block such as a new block showing up or periodically when there are // new transactions and enough time has elapsed without finding a solution. -func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int64, +func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int32, ticker *time.Ticker, quit chan struct{}) bool { // Choose a random extra nonce offset for this block template and diff --git a/database/db.go b/database/db.go index e17510de..8158d2af 100644 --- a/database/db.go +++ b/database/db.go @@ -28,7 +28,7 @@ var ( // AllShas is a special value that can be used as the final sha when requesting // a range of shas by height to request them all. -const AllShas = int64(^uint64(0) >> 1) +const AllShas = int32(^uint32(0) >> 1) // Db defines a generic interface that is used to request and insert data into // the bitcoin block chain. This interface is intended to be agnostic to actual @@ -53,7 +53,7 @@ type Db interface { FetchBlockBySha(sha *wire.ShaHash) (blk *btcutil.Block, err error) // FetchBlockHeightBySha returns the block height for the given hash. - FetchBlockHeightBySha(sha *wire.ShaHash) (height int64, err error) + FetchBlockHeightBySha(sha *wire.ShaHash) (height int32, err error) // FetchBlockHeaderBySha returns a wire.BlockHeader for the given // sha. The implementation may cache the underlying data if desired. @@ -61,13 +61,13 @@ type Db interface { // FetchBlockShaByHeight returns a block hash based on its height in the // block chain. - FetchBlockShaByHeight(height int64) (sha *wire.ShaHash, err error) + FetchBlockShaByHeight(height int32) (sha *wire.ShaHash, err error) // FetchHeightRange looks up a range of blocks by the start and ending // heights. Fetch is inclusive of the start height and exclusive of the // ending height. To fetch all hashes from the start height until no // more are present, use the special id `AllShas'. - FetchHeightRange(startHeight, endHeight int64) (rshalist []wire.ShaHash, err error) + FetchHeightRange(startHeight, endHeight int32) (rshalist []wire.ShaHash, err error) // ExistsTxSha returns whether or not the given tx hash is present in // the database @@ -103,19 +103,19 @@ type Db interface { // into the database. The first block inserted into the database // will be treated as the genesis block. Every subsequent block insert // requires the referenced parent block to already exist. - InsertBlock(block *btcutil.Block) (height int64, err error) + InsertBlock(block *btcutil.Block) (height int32, err error) // NewestSha returns the hash and block height of the most recent (end) // block of the block chain. It will return the zero hash, -1 for // the block height, and no error (nil) if there are not any blocks in // the database yet. - NewestSha() (sha *wire.ShaHash, height int64, err error) + NewestSha() (sha *wire.ShaHash, height int32, err error) // FetchAddrIndexTip returns the hash and block height of the most recent // block which has had its address index populated. It will return // ErrAddrIndexDoesNotExist along with a zero hash, and -1 if the // addrindex hasn't yet been built up. - FetchAddrIndexTip() (sha *wire.ShaHash, height int64, err error) + FetchAddrIndexTip() (sha *wire.ShaHash, height int32, err error) // UpdateAddrIndexForBlock updates the stored addrindex with passed // index information for a particular block height. Additionally, it @@ -124,7 +124,7 @@ type Db interface { // transaction which is commited before the function returns. // Addresses are indexed by the raw bytes of their base58 decoded // hash160. - UpdateAddrIndexForBlock(blkSha *wire.ShaHash, height int64, + UpdateAddrIndexForBlock(blkSha *wire.ShaHash, height int32, addrIndex BlockAddrIndex) error // FetchTxsForAddr looks up and returns all transactions which either @@ -162,7 +162,7 @@ type TxListReply struct { Sha *wire.ShaHash Tx *wire.MsgTx BlkSha *wire.ShaHash - Height int64 + Height int32 TxSpent []bool Err error } diff --git a/database/interface_test.go b/database/interface_test.go index e44eb765..7cd82ccf 100644 --- a/database/interface_test.go +++ b/database/interface_test.go @@ -26,7 +26,7 @@ type testContext struct { t *testing.T dbType string db database.Db - blockHeight int64 + blockHeight int32 blockHash *wire.ShaHash block *btcutil.Block useSpends bool @@ -213,7 +213,7 @@ func testFetchBlockShaByHeight(tc *testContext) bool { func testFetchBlockShaByHeightErrors(tc *testContext) bool { // Invalid heights must error and return a nil hash. - tests := []int64{-1, tc.blockHeight + 1, tc.blockHeight + 2} + tests := []int32{-1, tc.blockHeight + 1, tc.blockHeight + 2} for i, wantHeight := range tests { hashFromDb, err := tc.db.FetchBlockShaByHeight(wantHeight) if err == nil { @@ -545,7 +545,7 @@ func testInterface(t *testing.T, dbType string) { context := testContext{t: t, dbType: dbType, db: db} t.Logf("Loaded %d blocks for testing %s", len(blocks), dbType) - for height := int64(1); height < int64(len(blocks)); height++ { + for height := int32(1); height < int32(len(blocks)); height++ { // Get the appropriate block and hash and update the test // context accordingly. block := blocks[height] @@ -581,7 +581,7 @@ func testInterface(t *testing.T, dbType string) { // Run the data integrity tests again after all blocks have been // inserted to ensure the spend tracking is working properly. context.useSpends = true - for height := int64(0); height < int64(len(blocks)); height++ { + for height := int32(0); height < int32(len(blocks)); height++ { // Get the appropriate block and hash and update the // test context accordingly. block := blocks[height] @@ -613,14 +613,14 @@ func testInterface(t *testing.T, dbType string) { - DropAfterBlockBySha(*wire.ShaHash) (err error) x ExistsSha(sha *wire.ShaHash) (exists bool) x FetchBlockBySha(sha *wire.ShaHash) (blk *btcutil.Block, err error) - x FetchBlockShaByHeight(height int64) (sha *wire.ShaHash, err error) - - FetchHeightRange(startHeight, endHeight int64) (rshalist []wire.ShaHash, err error) + x FetchBlockShaByHeight(height int32) (sha *wire.ShaHash, err error) + - FetchHeightRange(startHeight, endHeight int32) (rshalist []wire.ShaHash, err error) x ExistsTxSha(sha *wire.ShaHash) (exists bool) x FetchTxBySha(txsha *wire.ShaHash) ([]*TxListReply, error) x FetchTxByShaList(txShaList []*wire.ShaHash) []*TxListReply x FetchUnSpentTxByShaList(txShaList []*wire.ShaHash) []*TxListReply - x InsertBlock(block *btcutil.Block) (height int64, err error) - x NewestSha() (sha *wire.ShaHash, height int64, err error) + x InsertBlock(block *btcutil.Block) (height int32, err error) + x NewestSha() (sha *wire.ShaHash, height int32, err error) - RollbackClose() - Sync() */ diff --git a/database/ldb/block.go b/database/ldb/block.go index 1079420d..b8becc33 100644 --- a/database/ldb/block.go +++ b/database/ldb/block.go @@ -41,7 +41,7 @@ func (db *LevelDb) fetchBlockBySha(sha *wire.ShaHash) (blk *btcutil.Block, err e // FetchBlockHeightBySha returns the block height for the given hash. This is // part of the database.Db interface implementation. -func (db *LevelDb) FetchBlockHeightBySha(sha *wire.ShaHash) (int64, error) { +func (db *LevelDb) FetchBlockHeightBySha(sha *wire.ShaHash) (int32, error) { db.dbLock.Lock() defer db.dbLock.Unlock() @@ -71,7 +71,7 @@ func (db *LevelDb) FetchBlockHeaderBySha(sha *wire.ShaHash) (bh *wire.BlockHeade return bh, err } -func (db *LevelDb) getBlkLoc(sha *wire.ShaHash) (int64, error) { +func (db *LevelDb) getBlkLoc(sha *wire.ShaHash) (int32, error) { key := shaBlkToKey(sha) data, err := db.lDb.Get(key, db.ro) @@ -85,13 +85,13 @@ func (db *LevelDb) getBlkLoc(sha *wire.ShaHash) (int64, error) { // deserialize blkHeight := binary.LittleEndian.Uint64(data) - return int64(blkHeight), nil + return int32(blkHeight), nil } -func (db *LevelDb) getBlkByHeight(blkHeight int64) (rsha *wire.ShaHash, rbuf []byte, err error) { +func (db *LevelDb) getBlkByHeight(blkHeight int32) (rsha *wire.ShaHash, rbuf []byte, err error) { var blkVal []byte - key := int64ToKey(blkHeight) + key := int64ToKey(int64(blkHeight)) blkVal, err = db.lDb.Get(key, db.ro) if err != nil { @@ -109,8 +109,8 @@ func (db *LevelDb) getBlkByHeight(blkHeight int64) (rsha *wire.ShaHash, rbuf []b return &sha, blockdata, nil } -func (db *LevelDb) getBlk(sha *wire.ShaHash) (rblkHeight int64, rbuf []byte, err error) { - var blkHeight int64 +func (db *LevelDb) getBlk(sha *wire.ShaHash) (rblkHeight int32, rbuf []byte, err error) { + var blkHeight int32 blkHeight, err = db.getBlkLoc(sha) if err != nil { @@ -126,13 +126,13 @@ func (db *LevelDb) getBlk(sha *wire.ShaHash) (rblkHeight int64, rbuf []byte, err return blkHeight, buf, nil } -func (db *LevelDb) setBlk(sha *wire.ShaHash, blkHeight int64, buf []byte) { +func (db *LevelDb) setBlk(sha *wire.ShaHash, blkHeight int32, buf []byte) { // serialize var lw [8]byte binary.LittleEndian.PutUint64(lw[0:8], uint64(blkHeight)) shaKey := shaBlkToKey(sha) - blkKey := int64ToKey(blkHeight) + blkKey := int64ToKey(int64(blkHeight)) blkVal := make([]byte, len(sha)+len(buf)) copy(blkVal[0:], sha[:]) @@ -145,7 +145,7 @@ func (db *LevelDb) setBlk(sha *wire.ShaHash, blkHeight int64, buf []byte) { // insertSha stores a block hash and its associated data block with a // previous sha of `prevSha'. // insertSha shall be called with db lock held -func (db *LevelDb) insertBlockData(sha *wire.ShaHash, prevSha *wire.ShaHash, buf []byte) (int64, error) { +func (db *LevelDb) insertBlockData(sha *wire.ShaHash, prevSha *wire.ShaHash, buf []byte) (int32, error) { oBlkHeight, err := db.getBlkLoc(prevSha) if err != nil { // check current block count @@ -175,8 +175,8 @@ func (db *LevelDb) insertBlockData(sha *wire.ShaHash, prevSha *wire.ShaHash, buf // fetchSha returns the datablock for the given ShaHash. func (db *LevelDb) fetchSha(sha *wire.ShaHash) (rbuf []byte, - rblkHeight int64, err error) { - var blkHeight int64 + rblkHeight int32, err error) { + var blkHeight int32 var buf []byte blkHeight, buf, err = db.getBlk(sha) @@ -208,7 +208,7 @@ func (db *LevelDb) blkExistsSha(sha *wire.ShaHash) (bool, error) { // FetchBlockShaByHeight returns a block hash based on its height in the // block chain. -func (db *LevelDb) FetchBlockShaByHeight(height int64) (sha *wire.ShaHash, err error) { +func (db *LevelDb) FetchBlockShaByHeight(height int32) (sha *wire.ShaHash, err error) { db.dbLock.Lock() defer db.dbLock.Unlock() @@ -217,8 +217,8 @@ func (db *LevelDb) FetchBlockShaByHeight(height int64) (sha *wire.ShaHash, err e // fetchBlockShaByHeight returns a block hash based on its height in the // block chain. -func (db *LevelDb) fetchBlockShaByHeight(height int64) (rsha *wire.ShaHash, err error) { - key := int64ToKey(height) +func (db *LevelDb) fetchBlockShaByHeight(height int32) (rsha *wire.ShaHash, err error) { + key := int64ToKey(int64(height)) blkVal, err := db.lDb.Get(key, db.ro) if err != nil { @@ -236,11 +236,11 @@ func (db *LevelDb) fetchBlockShaByHeight(height int64) (rsha *wire.ShaHash, err // heights. Fetch is inclusive of the start height and exclusive of the // ending height. To fetch all hashes from the start height until no // more are present, use the special id `AllShas'. -func (db *LevelDb) FetchHeightRange(startHeight, endHeight int64) (rshalist []wire.ShaHash, err error) { +func (db *LevelDb) FetchHeightRange(startHeight, endHeight int32) (rshalist []wire.ShaHash, err error) { db.dbLock.Lock() defer db.dbLock.Unlock() - var endidx int64 + var endidx int32 if endHeight == database.AllShas { endidx = startHeight + 500 } else { @@ -251,7 +251,7 @@ func (db *LevelDb) FetchHeightRange(startHeight, endHeight int64) (rshalist []wi for height := startHeight; height < endidx; height++ { // TODO(drahn) fix blkFile from height - key := int64ToKey(height) + key := int64ToKey(int64(height)) blkVal, lerr := db.lDb.Get(key, db.ro) if lerr != nil { break @@ -273,7 +273,7 @@ func (db *LevelDb) FetchHeightRange(startHeight, endHeight int64) (rshalist []wi // NewestSha returns the hash and block height of the most recent (end) block of // the block chain. It will return the zero hash, -1 for the block height, and // no error (nil) if there are not any blocks in the database yet. -func (db *LevelDb) NewestSha() (rsha *wire.ShaHash, rblkid int64, err error) { +func (db *LevelDb) NewestSha() (rsha *wire.ShaHash, rblkid int32, err error) { db.dbLock.Lock() defer db.dbLock.Unlock() @@ -312,7 +312,7 @@ func (db *LevelDb) checkAddrIndexVersion() error { // updated accordingly by functions that modify the state. This function is // used on start up to load the info into memory. Callers will use the public // version of this function below, which returns our cached copy. -func (db *LevelDb) fetchAddrIndexTip() (*wire.ShaHash, int64, error) { +func (db *LevelDb) fetchAddrIndexTip() (*wire.ShaHash, int32, error) { db.dbLock.Lock() defer db.dbLock.Unlock() @@ -326,14 +326,14 @@ func (db *LevelDb) fetchAddrIndexTip() (*wire.ShaHash, int64, error) { blkHeight := binary.LittleEndian.Uint64(data[32:]) - return &blkSha, int64(blkHeight), nil + return &blkSha, int32(blkHeight), nil } // FetchAddrIndexTip returns the hash and block height of the most recent // block whose transactions have been indexed by address. It will return // ErrAddrIndexDoesNotExist along with a zero hash, and -1 if the // addrindex hasn't yet been built up. -func (db *LevelDb) FetchAddrIndexTip() (*wire.ShaHash, int64, error) { +func (db *LevelDb) FetchAddrIndexTip() (*wire.ShaHash, int32, error) { db.dbLock.Lock() defer db.dbLock.Unlock() diff --git a/database/ldb/dup_test.go b/database/ldb/dup_test.go index 7bf6ab92..e797fa67 100644 --- a/database/ldb/dup_test.go +++ b/database/ldb/dup_test.go @@ -48,7 +48,7 @@ func Test_dupTx(t *testing.T) { // Populate with the fisrt 256 blocks, so we have blocks to 'mess with' err = nil out: - for height := int64(0); height < int64(len(blocks)); height++ { + for height := int32(0); height < int32(len(blocks)); height++ { block := blocks[height] // except for NoVerify which does not allow lookups check inputs diff --git a/database/ldb/insertremove_test.go b/database/ldb/insertremove_test.go index ea635b91..07c9144e 100644 --- a/database/ldb/insertremove_test.go +++ b/database/ldb/insertremove_test.go @@ -63,7 +63,7 @@ func testUnspentInsert(t *testing.T) { blocks := loadblocks(t) endtest: - for height := int64(0); height < int64(len(blocks)); height++ { + for height := int32(0); height < int32(len(blocks)); height++ { block := blocks[height] // look up inputs to this tx diff --git a/database/ldb/leveldb.go b/database/ldb/leveldb.go index 44d24005..01e1e763 100644 --- a/database/ldb/leveldb.go +++ b/database/ldb/leveldb.go @@ -29,7 +29,7 @@ var log = btclog.Disabled type tTxInsertData struct { txsha *wire.ShaHash - blockid int64 + blockid int32 txoff int txlen int usedbuf []byte @@ -47,14 +47,14 @@ type LevelDb struct { lbatch *leveldb.Batch - nextBlock int64 + nextBlock int32 lastBlkShaCached bool lastBlkSha wire.ShaHash - lastBlkIdx int64 + lastBlkIdx int32 lastAddrIndexBlkSha wire.ShaHash - lastAddrIndexBlkIdx int64 + lastAddrIndexBlkIdx int32 txUpdateMap map[wire.ShaHash]*txUpdateObj txSpentUpdateMap map[wire.ShaHash]*spentTxUpdate @@ -98,9 +98,9 @@ func OpenDB(args ...interface{}) (database.Db, error) { } // Need to find last block and tx - var lastknownblock, nextunknownblock, testblock int64 + var lastknownblock, nextunknownblock, testblock int32 - increment := int64(100000) + increment := int32(100000) ldb := db.(*LevelDb) var lastSha *wire.ShaHash @@ -345,7 +345,7 @@ func (db *LevelDb) DropAfterBlockBySha(sha *wire.ShaHash) (rerr error) { db.txUpdateMap[*tx.Sha()] = &txUo } db.lBatch().Delete(shaBlkToKey(blksha)) - db.lBatch().Delete(int64ToKey(height)) + db.lBatch().Delete(int64ToKey(int64(height))) } // update the last block cache @@ -361,7 +361,7 @@ func (db *LevelDb) DropAfterBlockBySha(sha *wire.ShaHash) (rerr error) { // database. The first block inserted into the database will be treated as the // genesis block. Every subsequent block insert requires the referenced parent // block to already exist. -func (db *LevelDb) InsertBlock(block *btcutil.Block) (height int64, rerr error) { +func (db *LevelDb) InsertBlock(block *btcutil.Block) (height int32, rerr error) { db.dbLock.Lock() defer db.dbLock.Unlock() defer func() { diff --git a/database/ldb/operational_test.go b/database/ldb/operational_test.go index 6767dc57..8072a884 100644 --- a/database/ldb/operational_test.go +++ b/database/ldb/operational_test.go @@ -72,7 +72,7 @@ func TestOperational(t *testing.T) { // testAddrIndexOperations ensures that all normal operations concerning // the optional address index function correctly. -func testAddrIndexOperations(t *testing.T, db database.Db, newestBlock *btcutil.Block, newestSha *wire.ShaHash, newestBlockIdx int64) { +func testAddrIndexOperations(t *testing.T, db database.Db, newestBlock *btcutil.Block, newestSha *wire.ShaHash, newestBlockIdx int32) { // Metadata about the current addr index state should be unset. sha, height, err := db.FetchAddrIndexTip() if err != database.ErrAddrIndexDoesNotExist { @@ -188,7 +188,7 @@ func testAddrIndexOperations(t *testing.T, db database.Db, newestBlock *btcutil. } -func assertAddrIndexTipIsUpdated(db database.Db, t *testing.T, newestSha *wire.ShaHash, newestBlockIdx int64) { +func assertAddrIndexTipIsUpdated(db database.Db, t *testing.T, newestSha *wire.ShaHash, newestBlockIdx int32) { // Safe to ignore error, since height will be < 0 in "error" case. sha, height, _ := db.FetchAddrIndexTip() if newestBlockIdx != height { @@ -215,7 +215,7 @@ func testOperationalMode(t *testing.T) { defer testDb.cleanUpFunc() err = nil out: - for height := int64(0); height < int64(len(testDb.blocks)); height++ { + for height := int32(0); height < int32(len(testDb.blocks)); height++ { block := testDb.blocks[height] mblock := block.MsgBlock() var txneededList []*wire.ShaHash @@ -306,7 +306,7 @@ func testBackout(t *testing.T) { } err = nil - for height := int64(0); height < int64(len(testDb.blocks)); height++ { + for height := int32(0); height < int32(len(testDb.blocks)); height++ { if height == 100 { t.Logf("Syncing at block height 100") testDb.db.Sync() @@ -417,7 +417,7 @@ func loadBlocks(t *testing.T, file string) (blocks []*btcutil.Block, err error) var block *btcutil.Block err = nil - for height := int64(1); err == nil; height++ { + for height := int32(1); err == nil; height++ { var rintbuf uint32 err = binary.Read(dr, binary.LittleEndian, &rintbuf) if err == io.EOF { @@ -456,18 +456,18 @@ func loadBlocks(t *testing.T, file string) (blocks []*btcutil.Block, err error) func testFetchHeightRange(t *testing.T, db database.Db, blocks []*btcutil.Block) { - var testincrement int64 = 50 - var testcnt int64 = 100 + var testincrement int32 = 50 + var testcnt int32 = 100 shanames := make([]*wire.ShaHash, len(blocks)) - nBlocks := int64(len(blocks)) + nBlocks := int32(len(blocks)) for i := range blocks { shanames[i] = blocks[i].Sha() } - for startheight := int64(0); startheight < nBlocks; startheight += testincrement { + for startheight := int32(0); startheight < nBlocks; startheight += testincrement { endheight := startheight + testcnt if endheight > nBlocks { @@ -480,20 +480,20 @@ func testFetchHeightRange(t *testing.T, db database.Db, blocks []*btcutil.Block) } if endheight == database.AllShas { - if int64(len(shalist)) != nBlocks-startheight { + if int32(len(shalist)) != nBlocks-startheight { t.Errorf("FetchHeightRange: expected A %v shas, got %v", nBlocks-startheight, len(shalist)) } } else { - if int64(len(shalist)) != testcnt { + if int32(len(shalist)) != testcnt { t.Errorf("FetchHeightRange: expected %v shas, got %v", testcnt, len(shalist)) } } for i := range shalist { - sha0 := *shanames[int64(i)+startheight] + sha0 := *shanames[int32(i)+startheight] sha1 := shalist[i] if sha0 != sha1 { - t.Errorf("FetchHeightRange: mismatch sha at %v requested range %v %v: %v %v ", int64(i)+startheight, startheight, endheight, sha0, sha1) + t.Errorf("FetchHeightRange: mismatch sha at %v requested range %v %v: %v %v ", int32(i)+startheight, startheight, endheight, sha0, sha1) } } } diff --git a/database/ldb/tx.go b/database/ldb/tx.go index b0f5586f..cf9e6243 100644 --- a/database/ldb/tx.go +++ b/database/ldb/tx.go @@ -46,7 +46,7 @@ var addrIndexVersionKey = []byte("addrindexversion") type txUpdateObj struct { txSha *wire.ShaHash - blkHeight int64 + blkHeight int32 txoff int txlen int ntxout int @@ -55,7 +55,7 @@ type txUpdateObj struct { } type spentTx struct { - blkHeight int64 + blkHeight int32 txoff int txlen int numTxO int @@ -68,13 +68,13 @@ type spentTxUpdate struct { type txAddrIndex struct { hash160 [ripemd160.Size]byte - blkHeight int64 + blkHeight int32 txoffset int txlen int } // InsertTx inserts a tx hash and its associated data into the database. -func (db *LevelDb) InsertTx(txsha *wire.ShaHash, height int64, txoff int, txlen int, spentbuf []byte) (err error) { +func (db *LevelDb) InsertTx(txsha *wire.ShaHash, height int32, txoff int, txlen int, spentbuf []byte) (err error) { db.dbLock.Lock() defer db.dbLock.Unlock() @@ -83,7 +83,7 @@ func (db *LevelDb) InsertTx(txsha *wire.ShaHash, height int64, txoff int, txlen // insertTx inserts a tx hash and its associated data into the database. // Must be called with db lock held. -func (db *LevelDb) insertTx(txSha *wire.ShaHash, height int64, txoff int, txlen int, spentbuf []byte) (err error) { +func (db *LevelDb) insertTx(txSha *wire.ShaHash, height int32, txoff int, txlen int, spentbuf []byte) (err error) { var txU txUpdateObj txU.txSha = txSha @@ -113,7 +113,7 @@ func (db *LevelDb) formatTx(txu *txUpdateObj) []byte { return txW[:] } -func (db *LevelDb) getTxData(txsha *wire.ShaHash) (int64, int, int, []byte, error) { +func (db *LevelDb) getTxData(txsha *wire.ShaHash) (int32, int, int, []byte, error) { key := shaTxToKey(txsha) buf, err := db.lDb.Get(key, db.ro) if err != nil { @@ -127,7 +127,7 @@ func (db *LevelDb) getTxData(txsha *wire.ShaHash) (int64, int, int, []byte, erro spentBuf := make([]byte, len(buf)-16) copy(spentBuf, buf[16:]) - return int64(blkHeight), int(txOff), int(txLen), spentBuf, nil + return int32(blkHeight), int(txOff), int(txLen), spentBuf, nil } func (db *LevelDb) getTxFullySpent(txsha *wire.ShaHash) ([]*spentTx, error) { @@ -153,7 +153,7 @@ func (db *LevelDb) getTxFullySpent(txsha *wire.ShaHash) ([]*spentTx, error) { numTxO := binary.LittleEndian.Uint32(buf[offset+16 : offset+20]) sTx := spentTx{ - blkHeight: int64(blkHeight), + blkHeight: int32(blkHeight), txoff: int(txOff), txlen: int(txLen), numTxO: int(numTxO), @@ -269,8 +269,8 @@ func (db *LevelDb) FetchUnSpentTxByShaList(txShaList []*wire.ShaHash) []*databas } // fetchTxDataBySha returns several pieces of data regarding the given sha. -func (db *LevelDb) fetchTxDataBySha(txsha *wire.ShaHash) (rtx *wire.MsgTx, rblksha *wire.ShaHash, rheight int64, rtxspent []byte, err error) { - var blkHeight int64 +func (db *LevelDb) fetchTxDataBySha(txsha *wire.ShaHash) (rtx *wire.MsgTx, rblksha *wire.ShaHash, rheight int32, rtxspent []byte, err error) { + var blkHeight int32 var txspent []byte var txOff, txLen int @@ -286,7 +286,7 @@ func (db *LevelDb) fetchTxDataBySha(txsha *wire.ShaHash) (rtx *wire.MsgTx, rblks // fetchTxDataByLoc returns several pieces of data regarding the given tx // located by the block/offset/size location -func (db *LevelDb) fetchTxDataByLoc(blkHeight int64, txOff int, txLen int, txspent []byte) (rtx *wire.MsgTx, rblksha *wire.ShaHash, rheight int64, rtxspent []byte, err error) { +func (db *LevelDb) fetchTxDataByLoc(blkHeight int32, txOff int, txLen int, txspent []byte) (rtx *wire.MsgTx, rblksha *wire.ShaHash, rheight int32, rtxspent []byte, err error) { var blksha *wire.ShaHash var blkbuf []byte @@ -401,7 +401,7 @@ func addrIndexToKey(index *txAddrIndex) []byte { // unpackTxIndex deserializes the raw bytes of a address tx index. func unpackTxIndex(rawIndex [12]byte) *txAddrIndex { return &txAddrIndex{ - blkHeight: int64(binary.BigEndian.Uint32(rawIndex[0:4])), + blkHeight: int32(binary.BigEndian.Uint32(rawIndex[0:4])), txoffset: int(binary.BigEndian.Uint32(rawIndex[4:8])), txlen: int(binary.BigEndian.Uint32(rawIndex[8:12])), } @@ -511,7 +511,7 @@ func (db *LevelDb) FetchTxsForAddr(addr btcutil.Address, skip int, // append-only list for the stored value. However, this add unnecessary // overhead when storing and retrieving since the entire list must // be fetched each time. -func (db *LevelDb) UpdateAddrIndexForBlock(blkSha *wire.ShaHash, blkHeight int64, addrIndex database.BlockAddrIndex) error { +func (db *LevelDb) UpdateAddrIndexForBlock(blkSha *wire.ShaHash, blkHeight int32, addrIndex database.BlockAddrIndex) error { db.dbLock.Lock() defer db.dbLock.Unlock() diff --git a/database/memdb/memdb.go b/database/memdb/memdb.go index 98deab29..25b86c9c 100644 --- a/database/memdb/memdb.go +++ b/database/memdb/memdb.go @@ -32,7 +32,7 @@ var ( // tTxInsertData holds information about the location and spent status of // a transaction. type tTxInsertData struct { - blockHeight int64 + blockHeight int32 offset int spentBuf []bool } @@ -86,7 +86,7 @@ type MemDb struct { // blocksBySha keeps track of block heights by hash. The height can // be used as an index into the blocks slice. - blocksBySha map[wire.ShaHash]int64 + blocksBySha map[wire.ShaHash]int32 // txns holds information about transactions such as which their // block height and spent status of all their outputs. @@ -177,7 +177,7 @@ func (db *MemDb) DropAfterBlockBySha(sha *wire.ShaHash) error { // backwards from the last block through the block just after the passed // block. While doing this unspend all transactions in each block and // remove the block. - endHeight := int64(len(db.blocks) - 1) + endHeight := int32(len(db.blocks) - 1) for i := endHeight; i > height; i-- { // Unspend and remove each transaction in reverse order because // later transactions in a block can reference earlier ones. @@ -237,7 +237,7 @@ func (db *MemDb) FetchBlockBySha(sha *wire.ShaHash) (*btcutil.Block, error) { // FetchBlockHeightBySha returns the block height for the given hash. This is // part of the database.Db interface implementation. -func (db *MemDb) FetchBlockHeightBySha(sha *wire.ShaHash) (int64, error) { +func (db *MemDb) FetchBlockHeightBySha(sha *wire.ShaHash) (int32, error) { db.Lock() defer db.Unlock() @@ -275,7 +275,7 @@ func (db *MemDb) FetchBlockHeaderBySha(sha *wire.ShaHash) (*wire.BlockHeader, er // FetchBlockShaByHeight returns a block hash based on its height in the block // chain. This is part of the database.Db interface implementation. -func (db *MemDb) FetchBlockShaByHeight(height int64) (*wire.ShaHash, error) { +func (db *MemDb) FetchBlockShaByHeight(height int32) (*wire.ShaHash, error) { db.Lock() defer db.Unlock() @@ -283,7 +283,7 @@ func (db *MemDb) FetchBlockShaByHeight(height int64) (*wire.ShaHash, error) { return nil, ErrDbClosed } - numBlocks := int64(len(db.blocks)) + numBlocks := int32(len(db.blocks)) if height < 0 || height > numBlocks-1 { return nil, fmt.Errorf("unable to fetch block height %d since "+ "it is not within the valid range (%d-%d)", height, 0, @@ -299,7 +299,7 @@ func (db *MemDb) FetchBlockShaByHeight(height int64) (*wire.ShaHash, error) { // Fetch is inclusive of the start height and exclusive of the ending height. // To fetch all hashes from the start height until no more are present, use the // special id `AllShas'. This is part of the database.Db interface implementation. -func (db *MemDb) FetchHeightRange(startHeight, endHeight int64) ([]wire.ShaHash, error) { +func (db *MemDb) FetchHeightRange(startHeight, endHeight int32) ([]wire.ShaHash, error) { db.Lock() defer db.Unlock() @@ -310,7 +310,7 @@ func (db *MemDb) FetchHeightRange(startHeight, endHeight int64) ([]wire.ShaHash, // When the user passes the special AllShas id, adjust the end height // accordingly. if endHeight == database.AllShas { - endHeight = int64(len(db.blocks)) + endHeight = int32(len(db.blocks)) } // Ensure requested heights are sane. @@ -325,7 +325,7 @@ func (db *MemDb) FetchHeightRange(startHeight, endHeight int64) ([]wire.ShaHash, } // Fetch as many as are availalbe within the specified range. - lastBlockIndex := int64(len(db.blocks) - 1) + lastBlockIndex := int32(len(db.blocks) - 1) hashList := make([]wire.ShaHash, 0, endHeight-startHeight) for i := startHeight; i < endHeight; i++ { if i > lastBlockIndex { @@ -515,7 +515,7 @@ func (db *MemDb) FetchUnSpentTxByShaList(txShaList []*wire.ShaHash) []*database. // genesis block. Every subsequent block insert requires the referenced parent // block to already exist. This is part of the database.Db interface // implementation. -func (db *MemDb) InsertBlock(block *btcutil.Block) (int64, error) { +func (db *MemDb) InsertBlock(block *btcutil.Block) (int32, error) { db.Lock() defer db.Unlock() @@ -547,7 +547,7 @@ func (db *MemDb) InsertBlock(block *btcutil.Block) (int64, error) { // Although these checks could could be done in the loop below, checking // for error conditions up front means the code below doesn't have to // deal with rollback on errors. - newHeight := int64(len(db.blocks)) + newHeight := int32(len(db.blocks)) for i, tx := range transactions { // Two old blocks contain duplicate transactions due to being // mined by faulty miners and accepted by the origin Satoshi @@ -656,7 +656,7 @@ func (db *MemDb) InsertBlock(block *btcutil.Block) (int64, error) { // the block chain. It will return the zero hash, -1 for the block height, and // no error (nil) if there are not any blocks in the database yet. This is part // of the database.Db interface implementation. -func (db *MemDb) NewestSha() (*wire.ShaHash, int64, error) { +func (db *MemDb) NewestSha() (*wire.ShaHash, int32, error) { db.Lock() defer db.Unlock() @@ -672,18 +672,18 @@ func (db *MemDb) NewestSha() (*wire.ShaHash, int64, error) { } blockSha := db.blocks[numBlocks-1].BlockSha() - return &blockSha, int64(numBlocks - 1), nil + return &blockSha, int32(numBlocks - 1), nil } // FetchAddrIndexTip isn't currently implemented. This is a part of the // database.Db interface implementation. -func (db *MemDb) FetchAddrIndexTip() (*wire.ShaHash, int64, error) { +func (db *MemDb) FetchAddrIndexTip() (*wire.ShaHash, int32, error) { return nil, 0, database.ErrNotImplemented } // UpdateAddrIndexForBlock isn't currently implemented. This is a part of the // database.Db interface implementation. -func (db *MemDb) UpdateAddrIndexForBlock(*wire.ShaHash, int64, +func (db *MemDb) UpdateAddrIndexForBlock(*wire.ShaHash, int32, database.BlockAddrIndex) error { return database.ErrNotImplemented } @@ -737,7 +737,7 @@ func (db *MemDb) Sync() error { func newMemDb() *MemDb { db := MemDb{ blocks: make([]*wire.MsgBlock, 0, 200000), - blocksBySha: make(map[wire.ShaHash]int64), + blocksBySha: make(map[wire.ShaHash]int32), txns: make(map[wire.ShaHash][]*tTxInsertData), } return &db diff --git a/database/reorg_test.go b/database/reorg_test.go index be03fc96..9fc2e1b2 100644 --- a/database/reorg_test.go +++ b/database/reorg_test.go @@ -33,7 +33,7 @@ func testReorganization(t *testing.T, dbType string) { t.Fatalf("Error loading file: %v", err) } - for i := int64(0); i <= 2; i++ { + for i := int32(0); i <= 2; i++ { _, err = db.InsertBlock(blocks[i]) if err != nil { t.Fatalf("Error inserting block %d (%v): %v", i, @@ -45,7 +45,7 @@ func testReorganization(t *testing.T, dbType string) { } } - for i := int64(1); i >= 0; i-- { + for i := int32(1); i >= 0; i-- { blkHash := blocks[i].Sha() err = db.DropAfterBlockBySha(blkHash) if err != nil { @@ -63,7 +63,7 @@ func testReorganization(t *testing.T, dbType string) { } } - for i := int64(3); i < int64(len(blocks)); i++ { + for i := int32(3); i < int32(len(blocks)); i++ { blkHash := blocks[i].Sha() if err != nil { t.Fatalf("Error getting SHA for block %dA: %v", i-2, err) @@ -79,7 +79,7 @@ func testReorganization(t *testing.T, dbType string) { t.Fatalf("Error getting newest block info") } - for i := int64(0); i <= maxHeight; i++ { + for i := int32(0); i <= maxHeight; i++ { blkHash, err := db.FetchBlockShaByHeight(i) if err != nil { t.Fatalf("Error fetching SHA for block %d: %v", i, err) @@ -126,7 +126,7 @@ func loadReorgBlocks(filename string) ([]*btcutil.Block, error) { var block *btcutil.Block err = nil - for height := int64(1); err == nil; height++ { + for height := int32(1); err == nil; height++ { var rintbuf uint32 err = binary.Read(dr, binary.LittleEndian, &rintbuf) if err == io.EOF { diff --git a/mempool.go b/mempool.go index 360ff80f..ddbd66aa 100644 --- a/mempool.go +++ b/mempool.go @@ -81,7 +81,7 @@ const ( type TxDesc struct { Tx *btcutil.Tx // Transaction. Added time.Time // Time when added to pool. - Height int64 // Blockheight when added to pool. + Height int32 // Blockheight when added to pool. Fee int64 // Transaction fees. startingPriority float64 // Priority when added to the pool. } @@ -228,7 +228,7 @@ func checkPkScriptStandard(pkScript []byte, scriptClass txscript.ScriptClass) er // finalized, conforming to more stringent size constraints, having scripts // of recognized forms, and not containing "dust" outputs (those that are // so small it costs more to process them than they are worth). -func (mp *txMemPool) checkTransactionStandard(tx *btcutil.Tx, height int64) error { +func (mp *txMemPool) checkTransactionStandard(tx *btcutil.Tx, height int32) error { msgTx := tx.MsgTx() // The transaction must be a currently supported version. @@ -700,7 +700,7 @@ func (mp *txMemPool) RemoveDoubleSpends(tx *btcutil.Tx) { // helper for maybeAcceptTransaction. // // This function MUST be called with the mempool lock held (for writes). -func (mp *txMemPool) addTransaction(tx *btcutil.Tx, height, fee int64) { +func (mp *txMemPool) addTransaction(tx *btcutil.Tx, height int32, fee int64) { // Add the transaction to the pool and mark the referenced outpoints // as spent by the pool. mp.pool[*tx.Sha()] = &TxDesc{ @@ -794,7 +794,7 @@ func (mp *txMemPool) indexScriptAddressToTx(pkScript []byte, tx *btcutil.Tx) err // age is the sum of this value for each txin. Any inputs to the transaction // which are currently in the mempool and hence not mined into a block yet, // contribute no additional input age to the transaction. -func calcInputValueAge(txDesc *TxDesc, txStore blockchain.TxStore, nextBlockHeight int64) float64 { +func calcInputValueAge(txDesc *TxDesc, txStore blockchain.TxStore, nextBlockHeight int32) float64 { var totalInputAge float64 for _, txIn := range txDesc.Tx.MsgTx().TxIn { originHash := &txIn.PreviousOutPoint.Hash @@ -807,7 +807,7 @@ func calcInputValueAge(txDesc *TxDesc, txStore blockchain.TxStore, nextBlockHeig // have their block height set to a special constant. // Their input age should computed as zero since their // parent hasn't made it into a block yet. - var inputAge int64 + var inputAge int32 if txData.BlockHeight == mempoolHeight { inputAge = 0 } else { @@ -817,7 +817,7 @@ func calcInputValueAge(txDesc *TxDesc, txStore blockchain.TxStore, nextBlockHeig // Sum the input value times age. originTxOut := txData.Tx.MsgTx().TxOut[originIndex] inputValue := originTxOut.Value - totalInputAge += float64(inputValue * inputAge) + totalInputAge += float64(inputValue * int64(inputAge)) } } @@ -890,7 +890,7 @@ func (txD *TxDesc) StartingPriority(txStore blockchain.TxStore) float64 { // CurrentPriority calculates the current priority of this tx descriptor's // underlying transaction relative to the next block height. -func (txD *TxDesc) CurrentPriority(txStore blockchain.TxStore, nextBlockHeight int64) float64 { +func (txD *TxDesc) CurrentPriority(txStore blockchain.TxStore, nextBlockHeight int32) float64 { inputAge := calcInputValueAge(txD, txStore, nextBlockHeight) return calcPriority(txD.Tx, inputAge) } diff --git a/mining.go b/mining.go index 4af91138..40f6d85b 100644 --- a/mining.go +++ b/mining.go @@ -158,7 +158,7 @@ type BlockTemplate struct { block *wire.MsgBlock fees []int64 sigOpCounts []int64 - height int64 + height int32 validPayAddress bool } @@ -180,8 +180,8 @@ func mergeTxStore(txStoreA blockchain.TxStore, txStoreB blockchain.TxStore) { // signature script of the coinbase transaction of a new block. In particular, // it starts with the block height that is required by version 2 blocks and adds // the extra nonce as well as additional coinbase flags. -func standardCoinbaseScript(nextBlockHeight int64, extraNonce uint64) ([]byte, error) { - return txscript.NewScriptBuilder().AddInt64(nextBlockHeight). +func standardCoinbaseScript(nextBlockHeight int32, extraNonce uint64) ([]byte, error) { + return txscript.NewScriptBuilder().AddInt64(int64(nextBlockHeight)). AddInt64(int64(extraNonce)).AddData([]byte(coinbaseFlags)). Script() } @@ -192,7 +192,7 @@ func standardCoinbaseScript(nextBlockHeight int64, extraNonce uint64) ([]byte, e // // See the comment for NewBlockTemplate for more information about why the nil // address handling is useful. -func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int64, addr btcutil.Address) (*btcutil.Tx, error) { +func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int32, addr btcutil.Address) (*btcutil.Tx, error) { // Create the script to pay to the provided payment address if one was // specified. Otherwise create a script that allows the coinbase to be // redeemable by anyone. @@ -232,7 +232,7 @@ func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int64, addr btcutil // spendTransaction updates the passed transaction store by marking the inputs // to the passed transaction as spent. It also adds the passed transaction to // the store at the provided height. -func spendTransaction(txStore blockchain.TxStore, tx *btcutil.Tx, height int64) error { +func spendTransaction(txStore blockchain.TxStore, tx *btcutil.Tx, height int32) error { for _, txIn := range tx.MsgTx().TxIn { originHash := &txIn.PreviousOutPoint.Hash originIndex := txIn.PreviousOutPoint.Index @@ -793,7 +793,7 @@ func UpdateBlockTime(msgBlock *wire.MsgBlock, bManager *blockManager) error { // block by regenerating the coinbase script with the passed value and block // height. It also recalculates and updates the new merkle root that results // from changing the coinbase script. -func UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight int64, extraNonce uint64) error { +func UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight int32, extraNonce uint64) error { coinbaseScript, err := standardCoinbaseScript(blockHeight, extraNonce) if err != nil { return err diff --git a/peer.go b/peer.go index ff430e0e..e35ca028 100644 --- a/peer.go +++ b/peer.go @@ -928,7 +928,7 @@ func (p *peer) handleGetBlocksMsg(msg *wire.MsgGetBlocks) { // provided locator are known. This does mean the client will start // over with the genesis block if unknown block locators are provided. // This mirrors the behavior in the reference implementation. - startIdx := int64(1) + startIdx := int32(1) for _, hash := range msg.BlockLocatorHashes { height, err := p.server.db.FetchBlockHeightBySha(hash) if err == nil { @@ -972,7 +972,7 @@ func (p *peer) handleGetBlocksMsg(msg *wire.MsgGetBlocks) { iv := wire.NewInvVect(wire.InvTypeBlock, &hashCopy) invMsg.AddInvVect(iv) } - start += int64(len(hashList)) + start += int32(len(hashList)) } // Send the inventory message if there is anything to send. @@ -1034,7 +1034,7 @@ func (p *peer) handleGetHeadersMsg(msg *wire.MsgGetHeaders) { // provided locator are known. This does mean the client will start // over with the genesis block if unknown block locators are provided. // This mirrors the behavior in the reference implementation. - startIdx := int64(1) + startIdx := int32(1) for _, hash := range msg.BlockLocatorHashes { height, err := p.server.db.FetchBlockHeightBySha(hash) if err == nil { @@ -1083,7 +1083,7 @@ func (p *peer) handleGetHeadersMsg(msg *wire.MsgGetHeaders) { // Start at the next block header after the latest one on the // next loop iteration. - start += int64(len(hashList)) + start += int32(len(hashList)) } p.QueueMessage(headersMsg, nil) } diff --git a/rpcserver.go b/rpcserver.go index 46a901a6..d095a0b3 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -676,7 +676,7 @@ func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params) []btcjson.Vou // to a raw transaction JSON object. func createTxRawResult(chainParams *chaincfg.Params, mtx *wire.MsgTx, txHash string, blkHeader *wire.BlockHeader, blkHash string, - blkHeight int64, chainHeight int64) (*btcjson.TxRawResult, error) { + blkHeight int32, chainHeight int32) (*btcjson.TxRawResult, error) { mtxHex, err := messageToHex(mtx) if err != nil { @@ -1013,7 +1013,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i Nonce: blockHeader.Nonce, Time: blockHeader.Timestamp.Unix(), Confirmations: uint64(1 + maxIdx - idx), - Height: idx, + Height: int64(idx), Size: int32(len(buf)), Bits: strconv.FormatInt(int64(blockHeader.Bits), 16), Difficulty: getDifficultyRatio(blockHeader.Bits), @@ -1045,7 +1045,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i // Get next block unless we are already at the top. if idx < maxIdx { var shaNext *wire.ShaHash - shaNext, err = s.server.db.FetchBlockShaByHeight(int64(idx + 1)) + shaNext, err = s.server.db.FetchBlockShaByHeight(idx + 1) if err != nil { context := "No next block" return nil, internalRPCError(err.Error(), context) @@ -1073,7 +1073,7 @@ func handleGetBlockCount(s *rpcServer, cmd interface{}, closeChan <-chan struct{ // handleGetBlockHash implements the getblockhash command. func handleGetBlockHash(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*btcjson.GetBlockHashCmd) - sha, err := s.server.db.FetchBlockShaByHeight(c.Index) + sha, err := s.server.db.FetchBlockShaByHeight(int32(c.Index)) if err != nil { return nil, &btcjson.RPCError{ Code: btcjson.ErrRPCOutOfRange, @@ -1109,7 +1109,7 @@ func handleGetBlockHeader(s *rpcServer, cmd interface{}, closeChan <-chan struct } var shaNextStr string - shaNext, err := s.server.db.FetchBlockShaByHeight(int64(blk.Height() + 1)) + shaNext, err := s.server.db.FetchBlockShaByHeight(blk.Height() + 1) if err == nil { shaNextStr = shaNext.String() } @@ -1510,7 +1510,7 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld reply := btcjson.GetBlockTemplateResult{ Bits: strconv.FormatInt(int64(header.Bits), 16), CurTime: header.Timestamp.Unix(), - Height: template.height, + Height: int64(template.height), PreviousHash: header.PrevBlock.String(), SigOpLimit: blockchain.MaxSigOpsPerBlock, SizeLimit: wire.MaxBlockPayload, @@ -2052,7 +2052,7 @@ func handleGetMiningInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{ } result := btcjson.GetMiningInfoResult{ - Blocks: height, + Blocks: int64(height), CurrentBlockSize: uint64(len(blockBytes)), CurrentBlockTx: uint64(len(block.MsgBlock().Transactions)), Difficulty: getDifficultyRatio(block.MsgBlock().Header.Bits), @@ -2095,9 +2095,9 @@ func handleGetNetworkHashPS(s *rpcServer, cmd interface{}, closeChan <-chan stru // since we can't reasonably calculate the number of network hashes // per second from invalid values. When it's negative, use the current // best block height. - endHeight := int64(-1) + endHeight := int32(-1) if c.Height != nil { - endHeight = int64(*c.Height) + endHeight = int32(*c.Height) } if endHeight > newestHeight || endHeight == 0 { return int64(0), nil @@ -2110,11 +2110,11 @@ func handleGetNetworkHashPS(s *rpcServer, cmd interface{}, closeChan <-chan stru // blocks. When the passed value is negative, use the last block the // difficulty changed as the starting height. Also make sure the // starting height is not before the beginning of the chain. - numBlocks := int64(120) + numBlocks := int32(120) if c.Blocks != nil { - numBlocks = int64(*c.Blocks) + numBlocks = int32(*c.Blocks) } - var startHeight int64 + var startHeight int32 if numBlocks <= 0 { startHeight = endHeight - ((endHeight % blockchain.BlocksPerRetarget) + 1) } else { @@ -2209,7 +2209,7 @@ func handleGetRawMempool(s *rpcServer, cmd interface{}, closeChan <-chan struct{ Size: int32(desc.Tx.MsgTx().SerializeSize()), Fee: btcutil.Amount(desc.Fee).ToBTC(), Time: desc.Added.Unix(), - Height: desc.Height, + Height: int64(desc.Height), StartingPriority: startingPriority, CurrentPriority: currentPriority, Depends: make([]string, 0), @@ -2252,7 +2252,7 @@ func handleGetRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan str // try the block database. var mtx *wire.MsgTx var blkHash *wire.ShaHash - var blkHeight int64 + var blkHeight int32 tx, err := s.server.txMemPool.FetchTransaction(txHash) if err != nil { txList, err := s.server.db.FetchTxBySha(txHash) @@ -2287,7 +2287,7 @@ func handleGetRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan str var blkHeader *wire.BlockHeader var blkHashStr string - var chainHeight int64 + var chainHeight int32 if blkHash != nil { blkHeader, err = s.server.db.FetchBlockHeaderBySha(blkHash) if err != nil { @@ -2364,7 +2364,7 @@ func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i // from there, otherwise attempt to fetch from the block database. var mtx *wire.MsgTx var bestBlockSha string - var confirmations int64 + var confirmations int32 var dbSpentInfo []bool includeMempool := true if c.IncludeMempool != nil { @@ -2450,7 +2450,7 @@ func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i txOutReply := &btcjson.GetTxOutResult{ BestBlock: bestBlockSha, - Confirmations: confirmations, + Confirmations: int64(confirmations), Value: btcutil.Amount(txOut.Value).ToUnit(btcutil.AmountBTC), Version: mtx.Version, ScriptPubKey: btcjson.ScriptPubKeyResult{ @@ -2946,7 +2946,7 @@ func handleSearchRawTransactions(s *rpcServer, cmd interface{}, closeChan <-chan // final JSON output (mempool won't have confirmations). var blkHeader *wire.BlockHeader var blkHashStr string - var blkHeight int64 + var blkHeight int32 if txReply.BlkSha != nil { blkHeader, err = s.server.db.FetchBlockHeaderBySha(txReply.BlkSha) if err != nil { @@ -3128,7 +3128,7 @@ func verifyChain(db database.Db, level, depth int32, timeSource blockchain.Media for height := curHeight; height > finishHeight; height-- { // Level 0 just looks up the block. - sha, err := db.FetchBlockShaByHeight(int64(height)) + sha, err := db.FetchBlockShaByHeight(height) if err != nil { rpcsLog.Errorf("Verify is unable to fetch block at "+ "height %d: %v", height, err) diff --git a/rpcwebsocket.go b/rpcwebsocket.go index 3c1781fc..725314c7 100644 --- a/rpcwebsocket.go +++ b/rpcwebsocket.go @@ -1759,7 +1759,7 @@ func rescanBlock(wsc *wsClient, lookups *rescanKeys, blk *btcutil.Block) { // verifies that the new range of blocks is on the same fork as a previous // range of blocks. If this condition does not hold true, the JSON-RPC error // for an unrecoverable reorganize is returned. -func recoverFromReorg(db database.Db, minBlock, maxBlock int64, +func recoverFromReorg(db database.Db, minBlock, maxBlock int32, lastBlock *wire.ShaHash) ([]wire.ShaHash, error) { hashList, err := db.FetchHeightRange(minBlock, maxBlock) @@ -2023,7 +2023,7 @@ fetchRange: // A goto is used to branch executation back to // before the range was evaluated, as it must be // reevaluated for the new hashList. - minBlock += int64(i) + minBlock += int32(i) hashList, err = recoverFromReorg(db, minBlock, maxBlock, lastBlockHash) if err != nil { @@ -2083,7 +2083,7 @@ fetchRange: } } - minBlock += int64(len(hashList)) + minBlock += int32(len(hashList)) } // Notify websocket client of the finished rescan. Due to how btcd