Compare commits

...

269 commits

Author SHA1 Message Date
Roy Lee
a0ff51b84a claimtrie: allows '*' in claim name 2022-11-23 08:50:17 -08:00
Roy Lee
4c39a9842c rpcclient: update rescanblockchain support 2022-10-31 00:23:46 -07:00
Roy Lee
f513fca6a7 lbcdblocknotify: reorganize the code with a few updates
1. Fixed a bug, which reads certs even TLS is disabled

2. Persists Stratum TCP connection with auto-reconnect.
   (retry backoff increases from 1s to 60s maximum)

3. Stratum update jobs on previous notifications are canceled
   when a new notification arrives.

   Usually, the jobs are so short and completed immediately.
   However, if the Stratum connection is broken, this prevents
   the bridge from accumulating stale jobs.
2022-10-17 00:03:13 -07:00
Alex Grintsvayg
6728bf4b08 error properly when lbcd fails to connect in HTTP POST mode
in the case where you're e.g. trying to connect to an
invalid address, the err vars in handleSendPostMessage()
were being shadowed inside the for loop. if c.httpClient.Do()
returned an error, that error never got returned upstream.
then ioutil.ReadAll(httpResponse.Body) would get a nil pointer
dereference. this fixes that case.
2022-10-14 11:40:46 -07:00
Roy Lee
979d643594 [lbry] claimtrie: created node cache 2022-09-29 16:45:42 -07:00
Roy Lee
cbc4d489e8 lbcctl: support --timed, --quiet options 2022-09-29 16:45:42 -07:00
Roy Lee
987a533423 rpc: update rpc cmd requests to support multi-account
Most of the updates add optional arguments with default
values.
2022-09-26 11:08:19 -07:00
Roy Lee
6bc9a2b4dd mining: always returns .coinbasevalue in getblocktemplate
Although the BIPs specify that coinbasetxn and coinbasevalue are
mutually exclusive, both the latest bitcoind (22.0.0) and lbrycrd
(0.17.3) return .coinbasevalue regardeless if 'coinbasetxn' is
specified in the capabilities.

We'll make lbcd behave the same for compatibility.
2022-09-25 18:48:59 -07:00
Roy Lee
9bcd3d0591 cotrib: add a helper script to show miner of a bkock 2022-09-23 17:49:01 -07:00
Roy Lee
2adfcd211d rpcclient: add -quiet option to the lbcdblocknotify example 2022-09-23 17:48:05 -07:00
Roy Lee
81ec217899 rpcserver: fix up getblockstats 2022-09-20 23:59:57 -07:00
Guilherme de Paula
5acfa4c81b rpcserver: add GetBlockStats 2022-09-20 23:59:57 -07:00
Roy Lee
c5193e74ac rpc: support hex data output for createrawtransaction 2022-09-14 18:41:04 -07:00
Roy Lee
8a80f0683a [lbry] policy: relax dust thrashold to 1000 dewies/kB
An output is considered dust if the cost to the network to spend the
coins is more than 1/3 of the minimum free transaction relay fee, which
has a default rate of 1000 satoshis/kb

bitcoind refactored dust threshold calculation, which removed the
multiply factor of 3 from the code, but increased the DUST_RELAY_TX_FEE
from 1000 to 3000 (satoshi/kb).

lbrycrd adopted the refactored code but also kept the rate to
1000 dewies/kB, which means:

    An output is considered dust if the cost to the network to spend the
    coins is more than the minimum free transaction relay fee.
2022-09-01 15:28:07 -07:00
Roy Lee
5d7a219e35 rpc: make getblock return orphan blocks with confirmation=-1 2022-08-31 18:32:49 -07:00
Roy Lee
2d04d31894 rpc: implement rescanblockchain rpcclient 2022-08-31 18:32:49 -07:00
Roy Lee
ce37025d5a txscript: validate claimscript size 2022-08-30 15:30:07 -07:00
Roy Lee
98e5771989 rpc: implement setban, lisnbanned, clearbanned RPCs 2022-08-14 21:26:27 -07:00
Roy Lee
ff324e0fdb doc: update snapshot related instructions 2022-08-14 14:17:41 -07:00
Roy Lee
be0d7de8da mining: accomodate pre-BIP0141 coinbase structure
Some popular pool software, yiimp for example, constructs coinbase
in pre-BIP0141 style, which results in rejection of submitblock.
2022-08-12 10:39:26 -07:00
Roy Lee
fcfb2af76f netsync: revert base/segwit encoding hack 2022-08-12 10:39:26 -07:00
Roy Lee
78bed14956 go mod: bump lbcutil to v1.0.202 2022-08-12 10:39:26 -07:00
Roy Lee
fdedbf86f8 mining: include 'segwit' rule when no segwit txns in GBT
According to the BIP0009, all active softfork deployment should
be included in the rules.

We add the '!' to indicate the enforcement if the template has
any segwit transactions in it. Otherwise, plain `segwit` is fine.
2022-08-08 00:49:16 -07:00
Roy Lee
a9351b3e3a lbcdblocknotify: support --run to execute custom command 2022-08-07 23:55:10 -07:00
Roy Lee
e323751218 ci: gofmt with go 1.19
Go 1.19 introduces various updates to gofmt.
2022-08-07 23:40:53 -07:00
Roy Lee
66c8567a27 ci: bump to Go 1.19 2022-08-07 23:40:17 -07:00
Roy Lee
6b0e7592c6 btcjson: remove WebsocketOnly for wallet extension RPCs 2022-07-29 12:10:53 -07:00
Roy Lee
05f52c11a1 docs: update README.md 2022-07-28 17:23:39 -07:00
Roy Lee
ea63a44c7b [lbry] rpcclient: fix stratum update_block format for blocknotify 2022-07-28 08:32:09 -07:00
Jonathan Moody
daa3137dc4 [rpc blockchain] Add support for mediantime, chainwork to RPC getblock. 2022-07-27 10:41:24 -07:00
Roy Lee
b147fe2a5b Revert "[lbry] claimtrie: created node cache"
This reverts commit 8f95946b17.
2022-07-27 10:18:35 -07:00
Jonathan Moody
7f9fe4b970 [rpc mempool] More tweaks to dynamicMemUsage(). Add toggleable assertions for max depth and switch completness. Toggle them when running in mempool_test.go. Drop support for reflect.Map, as it's not needed at this time. 2022-07-18 17:17:56 -07:00
Jonathan Moody
eefb1260eb [rpc mempool] Correct comment BTC -> LBC. 2022-07-18 17:17:56 -07:00
Jonathan Moody
a8a44aa988 [rpc mempool] Hide debugging functionality of dynamicMemUsage(). 2022-07-18 17:17:56 -07:00
Jonathan Moody
abb1b8b388 [rpc mempool] Add support for unbroadcastcount to RPC getmempoolinfo. 2022-07-18 17:17:56 -07:00
Jonathan Moody
13e31d033a [rpc mempool] Add support for usage, total_fee, mempoolminfee, minrelaytxfee to RPC getmempoolinfo. 2022-07-18 17:17:56 -07:00
Roy Lee
5499a2c1b3 [lbry] claimtrie: more verbose error message in ResetHeight 2022-07-17 11:32:33 -07:00
Roy Lee
fae4063046 rpc: remove deprecated and unimplemented 'move' 2022-07-14 15:45:06 -07:00
Roy Lee
8d1005706b rpc: remove deprecated and unimplemented 'setaccount' 2022-07-14 15:43:35 -07:00
Roy Lee
bb93a49349 [lbry] config: allow non-localhost connections with TLS disabled 2022-07-11 16:52:38 -07:00
Roy Lee
d5922cd725 [lbry] version: fix version string handling 2022-07-06 20:44:22 -07:00
Roy Lee
3a179a0eee [lbry] rpc: un-embedded attributes in getaddressinfo result
lbcwallet failed to re-generate RPC help message.

The help message generator doesn't handle embedded fields properly.
2022-07-05 20:12:27 -07:00
Jonathan Moody
ca9b4e5529 Rename nameProgressLogger -> claimProgressLogger and tweak log message. 2022-06-14 11:27:58 -07:00
Jonathan Moody
2b7f065855 Adjust and rename blockProgressLogger -> nameProgressLogger. Use it in makeNameHashNext() to track progress. 2022-06-14 11:27:58 -07:00
Jonathan Moody
b859832907 Copy netsync/blocklogger.go to claimtrie/logger.go. 2022-06-14 11:27:58 -07:00
Jonathan Moody
70852905e0 Allow environment var GOMAXPROCS=<N> to override NumCPU(). 2022-06-14 11:03:27 -07:00
Jonathan Moody
5f7b1f1b4f Copy value received by MergeOlder/MergeNewer so caller can't trash the merge result by modifying the contents. 2022-06-06 14:12:30 -07:00
Jonathan Moody
0241e18f42 Harden Marshal/Unmarshal logic for Change.SpentChildren. 2022-06-06 14:12:30 -07:00
Brannon King
b06df3d750 added buffer pool for pebble merge string 2022-06-06 14:12:30 -07:00
Jonathan Moody
15191b7ede
[lbry] runtime: Add --memprofile option
* Add --memprofile option. Add memprofile to sample config.
* Add --memprofile to doc.go.
2022-06-03 12:08:09 -07:00
Jonathan Moody
92a7a2087a
[lbry] runtime: Allow environment var GOGC=<percent> to override hard-coded SetGCPercent(10). 2022-06-03 09:19:55 -07:00
Brannon King
8f95946b17 [lbry] claimtrie: created node cache 2022-05-26 22:04:33 -07:00
Roy Lee
5d5f53c8d8 [lbry] contrib: add a helper script for generating snapshots 2022-05-26 21:53:59 -07:00
Roy Lee
6e36118193
[lbry] claimtrie: update CLI to support other tools
- fix default app dir name
- enable debug level for cli
- block sub command to output hash, height, or both
2022-05-26 21:52:15 -07:00
Roy Lee
e48200f53a [lbry] wire: limit the blocks of getdata message
In the cuurent codebase, OnGetData() handler penalizes / ban peers
requesting large blocks.

  server.go:
  @@ -649,7 +649,7 @@ func (sp *serverPeer) OnGetData(_ *peer.Peer, msg *wire.MsgGetData) {
          // bursts of small requests are not penalized as that would potentially ban
          // peers performing IBD.
          // This incremental score decays each minute to half of its value.
          if sp.addBanScore(0, uint32(length)*99/wire.MaxInvPerMsg, "getdata") {
                  return
          }

This accidentally penalize nodes trying to catch up checkpoints whose
'getdata' requests would be as large as the wire.MaxInvPerMsg, and get
banned very soon.

This patch limit getdata request to wire.MaxInvPerMsg/99 blocks.
2022-05-25 22:00:38 -07:00
Roy Lee
4a8d390a06
[lbry] ci: GoReleaser zero out buildid for reproducible builds (#40) 2022-05-25 21:49:12 -07:00
Roy Lee
aef4e45bd7 [lbry] ci: add github workflows 2022-05-24 02:49:08 -07:00
Roy Lee
0375a6d38b [lbry] ci: support GoReleaser 2022-05-24 02:35:27 -07:00
Roy Lee
2cfa235a33 [lbry] ci: update Dockerfile
Use $ARCH/debian:bullseye-20220418-slim as base image
2022-05-24 00:47:34 -07:00
Roy Lee
7ee3d7d26b [lbry] ci: add .golangci-lint.yml 2022-05-24 00:47:34 -07:00
Roy Lee
d4cddda35c [lbry] ci: update gocelan.sh 2022-05-24 00:41:56 -07:00
Roy Lee
76e482bb73 [lbry] ci: remove release/release.sh 2022-05-24 00:39:44 -07:00
Roy Lee
badb894e3a [lbry] ci: update .gitignore 2022-05-24 00:39:44 -07:00
Roy Lee
3cb961257c [lbry] ci: fixed various lint errors 2022-05-24 00:39:44 -07:00
Roy Lee
bf7a513006 [lbry] go mod: update go modules 2022-05-24 00:04:19 -07:00
Roy Lee
7c5a2c6f58 [lbry] version: update codebase to use version package 2022-05-24 00:04:19 -07:00
Roy Lee
3662f316ab [lbry] version: add version package 2022-05-24 00:04:19 -07:00
Roy Lee
43d3086ce1 [lbry] mempool: update getrawmempool and implement getmempoolentry
TODO::
1. Populate Ancestor and decsendent related fields instead of mocking.
2. Move and refator the implementation of getmempoolentry to the mempool
   package.
2022-05-24 00:04:19 -07:00
Roy Lee
7513046f70 [lbry] fees: replace estimatefee with esimatesmartfee 2022-05-24 00:04:19 -07:00
Roy Lee
d126d0c10e [lbry] fees: port estimatesmartfee from DCRD
1. logger
2. blockheight: int64 -> int32
3. dcrutil -> lbcutl
4. MaxConfirimation: 42
5. MinBucketFee: mempool.MinRelayFee (default 1000)
6. BucketFee Spacing: 1.1 -> 1.05

Note:
  DCRD implementation of estimatesmartfee is based on bitcoin core 0.14
  Lbrycrd (0.17) includes the updates of bitcoin core 0.15.
  They are slightly different, but shouldn't matter much.
2022-05-24 00:04:19 -07:00
Roy Lee
324c443c64 [lbry] fees: initial import from DCRD
vendored https://github.com/decred/dcrd/tree/master/internal/fees

Commit of the last modification

    commit a6e205b88fbb44f7ee85be25a81f4dad155670d8
    Author: Dave Collins <davec@conformal.com>
    Date:   Sat Dec 26 12:17:48 2020 -0600

        fees: Remove deprecated DisableLog.
2022-05-24 00:04:19 -07:00
Roy Lee
d99883a620 [lbry] btcjson: take integers for boolean parameters.
This is for backward compatibility with lbrycrd/bitcoind where some clients
use intger values (0/1) for boolean.
2022-05-24 00:04:19 -07:00
Roy Lee
a7f971f404 [lbry] rpc: update getrawtransaction to take verbose as boolean 2022-05-24 00:04:19 -07:00
Jeffrey Picard
239d681f28 [lbry] contrib: add linode deployment using docker 2022-05-24 00:04:19 -07:00
Roy Lee
d35a82412f [lbry] align port settings between lbcd, lbcctl, and lbcwallet 2022-05-24 00:01:46 -07:00
Brannon King
2bd6e4c3a9 [lbry] ffldb: increase open file limit and flush more often 2022-05-24 00:01:46 -07:00
Brannon King
b4623ef2dd [lbry] increase open file limit to 2048 2022-05-24 00:01:46 -07:00
Brannon King
4dd4505706 [lbry] docs: update docs for LBRY
Co-authored-by: Roy Lee <roylee17@gmail.com>
2022-05-24 00:01:46 -07:00
Brannon King
1b823c055f [lbry] test: don't remove old regression DB 2022-05-24 00:01:46 -07:00
Brannon King
a07bb527df [lbry] test: fixed all current tests and delete three.
Co-authored-by: Roy Lee <roylee17@gmail.com>
2022-05-24 00:01:46 -07:00
Brannon King
d6a6b53551 [lbry] upnp: brought in upnp fix from dcrd 2022-05-24 00:01:46 -07:00
Jonathan Moody
fe1637c223 [lbry] config: Verify completeness of sample-lbcd.conf using reflection on config struct. 2022-05-24 00:01:46 -07:00
Jonathan Moody
6c2a3d8bcf [lbry] config: Embed sample-lbcd.conf contents at build time.
Use embedded config if the sample-lbcd.conf is not found at runtime.
2022-05-24 00:01:46 -07:00
Jonathan Moody
2add30af9a [lbry] config: Add a number of missing options to sample-lbcd.conf.
Correct "blacklist is applied before the blacklist" typo in help text.
2022-05-24 00:01:46 -07:00
Roy Lee
b8b2bd1584 [lbry] config: enable txindex by default 2022-05-24 00:01:46 -07:00
Brannon King
f3e1c96de9 [lbry] config: enable upnp by default 2022-05-24 00:01:46 -07:00
Brannon King
0a0e79bc41 [lbry] enable segwit 2022-05-24 00:01:45 -07:00
Brannon King
023aa5d6b0 [lbry] btcjson: added optional address type for getnewaddress 2022-05-24 00:01:45 -07:00
Brannon King
de2a548207 [lbry] btcjson: ladded claim related fields for wallet 2022-05-24 00:01:45 -07:00
Roy Lee
568544961f [lbry] rpcserver: log the reason of submitblock rejection 2022-05-24 00:01:45 -07:00
Brannon King
8c984993a8 [lbry] rpcserver: made invalidate/reconsiderBlock return RPC errors 2022-05-24 00:01:45 -07:00
Brannon King
6c0360fa42 [lbry] rpcserver: made estimatesmartfee call estimatefee (for now) 2022-05-24 00:01:45 -07:00
Roy Lee
d20a2e53b4 [lbry] mining: return witness_script instead of raw witness_commitment in GBT 2022-05-24 00:01:45 -07:00
Roy Lee
29f64f9dcf [lbry] mining: enlarge updateHash channel buffers 2022-05-24 00:01:45 -07:00
Brannon King
e0870db24e [lbry] mining: calculate claimtrie root hash for generate RPC 2022-05-24 00:01:45 -07:00
Brannon King
6784830246 [lbry] blockchain: clear statusValid upon statusValidateFailed is set
The status management of index does need some refactoring.
For now, we just manually clear the statusValid in every occurance
of statusValidateFailed being set.

Co-authored-by: Roy Lee <roylee17@gmail.com>
2022-05-24 00:01:45 -07:00
Brannon King
405897fa38 [lbry] blockchain: fix crash on unlock generate/invalidate loop 2022-05-24 00:01:45 -07:00
Roy Lee
64884458f9 [lbry] rpc, mining: fix generatetoaddress 2022-05-24 00:01:45 -07:00
Alex Grintsvayg
5537ebbf0c [lbry] rpc: add GetChainTips rpc command 2022-05-24 00:01:45 -07:00
Brannon King
1ea849d509 [lbry] rpc: added getchaintips RPC
remove btcjson dep in chainquery
2022-05-24 00:01:45 -07:00
Brannon King
73d8f4762f [lbry] rpc: import invalidate/reconsiderblock from bchd 2022-05-24 00:01:45 -07:00
Brannon King
81862c664e [lbry] rpc: import getnetworkinfo from bchd 2022-05-24 00:01:45 -07:00
Brannon King
5116f45617 [lbry] rpc: fix getblock reponse 2022-05-24 00:01:45 -07:00
Brannon King
3d8f36a505 [lbry] rpc: output segwit rule 2022-05-24 00:01:45 -07:00
Roy Lee
096dd3ff75 [lbry] rpcclient: fix http response resource leaking 2022-05-24 00:01:02 -07:00
Roy Lee
fb3ef35189 [lbry] rpcclient: support SkipVerify of TLS certificate. (#39) 2022-05-23 23:53:30 -07:00
Roy Lee
3111601ac9 [lbry] rpcclient: add a blocknotify example using lbcd websocket 2022-05-23 23:53:30 -07:00
Brannon King
e7d8637cc5 [lbry] rpcclient: update defaultMaxFeeRate from 0.1 LBC to 0.5 LBC 2022-05-23 23:53:30 -07:00
Brannon King
9d70ff6f6d [lbry] rpcserver: add ClaimTrie root hash to GetBlockTemplate() 2022-05-23 23:53:30 -07:00
Brannon King
6834591d52 [lbry] rpc: support claim related methods 2022-05-23 23:53:30 -07:00
Brannon King
0c5f94420a [lbry] print out memory usage periodically 2022-05-23 23:53:30 -07:00
Roy Lee
6828cf5e36 [lbry] claimtrie: import current snapshot
Sync to tip

Co-authored-by: Brannon King <countprimes@gmail.com>
2022-05-23 23:53:30 -07:00
Roy Lee
45627c7a6a [lbry] rename btcd to lbcd
Co-authored-by: Brannon King <countprimes@gmail.com>
2022-05-23 23:53:30 -07:00
Roy Lee
aae5b24bb0 [lbry] blockchain: connect to ClaimTrie
Co-authored-by: Brannon King <countprimes@gmail.com>
2022-05-23 23:53:30 -07:00
Brannon King
ba22414cc1 [lbry] log: support claimtrie entries 2022-05-23 23:53:30 -07:00
Brannon King
78d780263b [lbry] txscript: remove claim prefix for addr calculation 2022-05-23 23:53:30 -07:00
Roy Lee
61a18152e9 [lbry] txscript: recognize LBRY claim script OPCODES 2022-05-23 23:53:30 -07:00
Roy Lee
2b28dfa528 [lbry] txscript: introduce claim script
Co-authored-by: Brannon King <countprimes@gmail.com>
2022-05-23 23:53:30 -07:00
Roy Lee
7657419b22 [lbry] txscript: change MaxScriptSize from 10,000 to 20,005 2022-05-23 23:53:30 -07:00
Alex Grintsvayg
33328a3e93 [lbry] server: make uptime rpc return a real uptime 2022-05-23 23:53:30 -07:00
Brannon King
44dd82a9f5 [lbry] server: don't ban peers on tx-not-in-block behavior 2022-05-23 23:53:30 -07:00
Roy Lee
93481d7f3a [lbry] server: update client version to /btcwire:0.5.0/LBRY.GO:0.12.2/
TODO: double check if lbryd bumps the version.
2022-05-23 23:53:30 -07:00
Brannon King
4eb4dfa670 [lbry] blockchain: Consider a block with timestamp less 6 hours 'current' 2022-05-23 23:53:30 -07:00
Brannon King
8ff0f3787e [lbry] blockchain: support force active fork deployment 2022-05-23 23:53:29 -07:00
Roy Lee
4a987b068d [lbry] blockchain, mempool: validate txscripts
Co-authored-by: Brannon King <countprimes@gmail.com>
2022-05-23 23:53:29 -07:00
Roy Lee
767a375816 [lbry] blockchain: change Block Subsidy algorithm 2022-05-23 23:53:29 -07:00
Roy Lee
e63ede0311 [lbry] blockchain: change the difficulty adjustment algorithm.
adjusted := target + (actual - target) / 8

  max := target + (target / 2)
  min := target - (target / 8)

  if adjusted > max {
    adjusted = max
  } else if adj < min {
    adjusted = min
  }

  diffculty := lastDifficulty * adjusted / target
2022-05-23 23:53:29 -07:00
Roy Lee
4bfd69e23d [lbry] blockchain: make UTXO in Genesis block spendable 2022-05-23 23:53:29 -07:00
Roy Lee
b2d0ae301e [lbry] blockchain, txscript: change maxScriptElementSize from 520 t0 20,000 bytes 2022-05-23 23:53:29 -07:00
Roy Lee
03989a91d9 [lbry] blockchain, wire: verify blockheaders using LBRY PoW 2022-05-23 23:53:29 -07:00
Roy Lee
9f479837c1 [lbry] blockchain: change max block size to 2,000,000 2022-05-23 23:53:29 -07:00
Roy Lee
3dc91f1295 [lbry] blockchain, wire: add ClaimTrie to Block Header 2022-05-23 23:53:29 -07:00
Roy Lee
cbac056756 [lbry] chaincfg: update chainparams for LBRY chain
Co-authored-by: Brannon King <countprimes@gmail.com>
Co-authored-by: Alex Grintsvayg <grin@lbry.com>
2022-05-23 23:53:29 -07:00
Roy Lee
ba3ca3b77e [lbry] chaincfg: setup genisis blocks 2022-05-23 23:53:29 -07:00
Roy Lee
21ad6495b6 [lbry] chaincfg: implement LBRY PoW Hash 2022-05-23 23:53:29 -07:00
Brannon King
dba1eb7261 [lbry] profile: support fgprof (flame graph) 2022-05-23 23:53:29 -07:00
Roy Lee
31d3d9debc [lbry] wire: increase wire.MaxBlockPayload to 8MB 2022-05-23 23:53:29 -07:00
Roy Lee
abe121ea6e [lbry] wire: update protocol NetIDs 2022-05-23 21:46:22 -07:00
Brannon King
2c3c4db198 [lbry] wire: optimize binaryFreeList handling 2022-05-23 21:46:22 -07:00
Tomasz Ziolkowski
a8ad257660 reduce redundant memory allocatio - resolves btcsuite/btcd#1699
Signed-off-by: Tomasz Ziolkowski <tomasz.ziolkowski@allegro.pl>
2022-05-23 21:46:22 -07:00
Calvin Kim
40dab558f6 go.mod, go.sum: Update goleveldb
Goleveldb recently had a PR in where memory allocation was reduced
drastically (github.com/syndtr/goleveldb/pull/367).  Update goleveldb
to use that PR.
2022-05-23 21:46:22 -07:00
Dave Collins
42310f6948 txscript: Make op callbacks take opcode and data.
This converts the callback function defined on the internal opcode
struct to accept the opcode and data slice instead of a parsed opcode as
the final step towards removing the parsed opcode struct and associated
supporting code altogether.

It also updates all of the callbacks and tests accordingly and finally
removes the now unused parsedOpcode struct.

The final results for the raw script analysis and tokenizer
optimizations are as follows:

benchmark                                       old ns/op     new ns/op     delta
BenchmarkIsPayToScriptHash-8                    62393         0.51          -100.00%
BenchmarkIsPubKeyHashScript-8                   62228         0.56          -100.00%
BenchmarkGetSigOpCount-8                        61051         658           -98.92%
BenchmarkExtractPkScriptAddrsLarge-8            60713         17.2          -99.97%
BenchmarkExtractPkScriptAddrs-8                 289           17.9          -93.81%
BenchmarkIsWitnessPubKeyHash-8                  61688         0.42          -100.00%
BenchmarkIsUnspendable-8                        656           520           -20.73%
BenchmarkExtractAtomicSwapDataPushesLarge-8     61332         44.0          -99.93%
BenchmarkExtractAtomicSwapDataPushes-8          990           260           -73.74%
BenchmarkDisasmString-8                         102902        39754         -61.37%
BenchmarkGetPreciseSigOpCount-8                 130223        715           -99.45%
BenchmarkScriptParsing-8                        63464         681           -98.93%
BenchmarkIsMultisigScriptLarge-8                64166         5.83          -99.99%
BenchmarkIsMultisigScript-8                     630           58.5          -90.71%
BenchmarkPushedData-8                           64837         1779          -97.26%
BenchmarkCalcSigHash-8                          3627895       3605459       -0.62%
BenchmarkIsPubKeyScript-8                       62323         2.83          -100.00%
BenchmarkIsPushOnlyScript-8                     62412         569           -99.09%
BenchmarkIsWitnessScriptHash-8                  61243         0.56          -100.00%
BenchmarkGetScriptClass-8                       61515         16.4          -99.97%
BenchmarkIsNullDataScript-8                     62495         2.53          -100.00%
BenchmarkIsMultisigSigScriptLarge-8             69328         2.52          -100.00%
BenchmarkIsMultisigSigScript-8                  2375          141           -94.06%
BenchmarkGetWitnessSigOpCountP2WKH-8            504           72.0          -85.71%
BenchmarkGetWitnessSigOpCountNested-8           1158          136           -88.26%
BenchmarkIsWitnessPubKeyHash-8                  68927         0.53          -100.00%
BenchmarkIsWitnessScriptHash-8                  62774         0.63          -100.00%

benchmark                                       old allocs     new allocs     delta
BenchmarkIsPayToScriptHash-8                    1              0              -100.00%
BenchmarkIsPubKeyHashScript-8                   1              0              -100.00%
BenchmarkGetSigOpCount-8                        1              0              -100.00%
BenchmarkExtractPkScriptAddrsLarge-8            1              0              -100.00%
BenchmarkExtractPkScriptAddrs-8                 1              0              -100.00%
BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
BenchmarkIsUnspendable-8                        1              0              -100.00%
BenchmarkExtractAtomicSwapDataPushesLarge-8     1              0              -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          2              1              -50.00%
BenchmarkDisasmString-8                         46             51             +10.87%
BenchmarkGetPreciseSigOpCount-8                 3              0              -100.00%
BenchmarkScriptParsing-8                        1              0              -100.00%
BenchmarkIsMultisigScriptLarge-8                1              0              -100.00%
BenchmarkIsMultisigScript-8                     1              0              -100.00%
BenchmarkPushedData-8                           7              6              -14.29%
BenchmarkCalcSigHash-8                          1335           712            -46.67%
BenchmarkIsPubKeyScript-8                       1              0              -100.00%
BenchmarkIsPushOnlyScript-8                     1              0              -100.00%
BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%
BenchmarkGetScriptClass-8                       1              0              -100.00%
BenchmarkIsNullDataScript-8                     1              0              -100.00%
BenchmarkIsMultisigSigScriptLarge-8             5              0              -100.00%
BenchmarkIsMultisigSigScript-8                  3              0              -100.00%
BenchmarkGetWitnessSigOpCountP2WKH-8            2              0              -100.00%
BenchmarkGetWitnessSigOpCountNested-8           4              0              -100.00%
BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%

benchmark                                       old bytes     new bytes     delta
BenchmarkIsPayToScriptHash-8                    311299        0             -100.00%
BenchmarkIsPubKeyHashScript-8                   311299        0             -100.00%
BenchmarkGetSigOpCount-8                        311299        0             -100.00%
BenchmarkExtractPkScriptAddrsLarge-8            311299        0             -100.00%
BenchmarkExtractPkScriptAddrs-8                 768           0             -100.00%
BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
BenchmarkIsUnspendable-8                        1             0             -100.00%
BenchmarkExtractAtomicSwapDataPushesLarge-8     311299        0             -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          3168          96            -96.97%
BenchmarkDisasmString-8                         389324        130552        -66.47%
BenchmarkGetPreciseSigOpCount-8                 623367        0             -100.00%
BenchmarkScriptParsing-8                        311299        0             -100.00%
BenchmarkIsMultisigScriptLarge-8                311299        0             -100.00%
BenchmarkIsMultisigScript-8                     2304          0             -100.00%
BenchmarkPushedData-8                           312816        1520          -99.51%
BenchmarkCalcSigHash-8                          1373812       1290507       -6.06%
BenchmarkIsPubKeyScript-8                       311299        0             -100.00%
BenchmarkIsPushOnlyScript-8                     311299        0             -100.00%
BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%
BenchmarkGetScriptClass-8                       311299        0             -100.00%
BenchmarkIsNullDataScript-8                     311299        0             -100.00%
BenchmarkIsMultisigSigScriptLarge-8             330035        0             -100.00%
BenchmarkIsMultisigSigScript-8                  9472          0             -100.00%
BenchmarkGetWitnessSigOpCountP2WKH-8            1408          0             -100.00%
BenchmarkGetWitnessSigOpCountNested-8           3200          0             -100.00%
BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%
2022-05-23 21:46:22 -07:00
Dave Collins
7358671e83 txscript: Make executeOpcode take opcode and data.
This converts the executeOpcode function defined on the engine to accept
an opcode and data slice instead of a parsed opcode as a step towards
removing the parsed opcode struct and associated supporting code altogether.

It also updates all callers accordingly.
2022-05-23 21:46:21 -07:00
Dave Collins
6f3f4c1b8c txscript: Remove unused parseScriptTemplate func.
Also remove tests associated with the func accordingly.
2022-05-23 21:46:21 -07:00
Dave Collins
4bbfd2413c txscript: Remove unused parsedOpcode.bytes func. 2022-05-23 21:46:21 -07:00
Dave Collins
849873675f txscript: Remove unused unparseScript func.
Also remove tests associated with unparsing opcodes accordingly.
2022-05-23 21:46:21 -07:00
Conner Fromknecht
82e02951dc txscript: Remove unused calcWitnessSignatureHash 2022-05-23 21:46:21 -07:00
Dave Collins
08a53b25fb txscript: Remove unused parseScript func. 2022-05-23 21:46:21 -07:00
Conner Fromknecht
8588536586 txscript/pkscript: Use finalOpcodeData to extract redeem script 2022-05-23 21:46:21 -07:00
Conner Fromknecht
e84398d21e txscript/sign: Use calcWitnessSigHashRaw for witness sigs 2022-05-23 21:46:21 -07:00
Conner Fromknecht
b40859ff00 txscript: Rename calcSignatureHashRaw 2022-05-23 21:46:21 -07:00
Dave Collins
9d1d6d59a6 txscript: Rename removeOpcodeByDataRaw func.
This renames the removeOpcodeByDataRaw to removeOpcodeByData now that
the old version has been removed.
2022-05-23 21:46:21 -07:00
Dave Collins
64aeab7882 txscript: Remove unused removeOpcodeByData func. 2022-05-23 21:46:21 -07:00
Conner Fromknecht
aa1014c87b txscript: Remove unused isWitnessProgram 2022-05-23 21:46:21 -07:00
Conner Fromknecht
bd07a2580e txscript: Remove unused calcSignatureHash 2022-05-23 21:46:21 -07:00
Dave Collins
b871286f98 txscript: Refactor engine to use raw scripts.
This refactors the script engine to store and step through raw scripts
by making using of the new zero-allocation script tokenizer as opposed
to the less efficient method of storing and stepping through parsed
opcodes.  It also improves several aspects while refactoring such as
optimizing the disassembly trace, showing all scripts in the trace in
the case of execution failure, and providing additional comments
describing the purpose of each field in the engine.

It should be noted that this is a step towards removing the parsed
opcode struct and associated supporting code altogether, however, in
order to ease the review process, this retains the struct and all
function signatures for opcode execution which make use of an individual
parsed opcode.  Those will be updated in future commits.

The following is an overview of the changes:

- Modify internal engine scripts slice to use raw scripts instead of
  parsed opcodes
- Introduce a tokenizer to the engine to track the current script
- Remove no longer needed script offset parameter from the engine since
  that is tracked by the tokenizer
- Add an opcode index counter for disassembly purposes to the engine
- Update check for valid program counter to only consider the script
  index
  - Update tests for bad program counter accordingly
- Rework the NewEngine function
  - Store the raw scripts
  - Setup the initial tokenizer
  - Explicitly check against version 0 instead of DefaultScriptVersion
    which would break consensus if changed
  - Check the scripts parse according to version 0 semantics to retain
    current consensus rules
  - Improve comments throughout
- Rework the Step function
  - Use the tokenizer and raw scripts
  - Create a parsed opcode on the fly for now to retain existing
    opcode execution function signatures
  - Improve comments throughout
- Update the Execute function
  - Explicitly check against version 0 instead of DefaultScriptVersion
    which would break consensus if changed
  - Improve the disassembly tracing in the case of error
- Update the CheckErrorCondition function
  - Modify clean stack error message to make sense in all cases
  - Improve the comments
- Update the DisasmPC and DisasmScript functions on the engine
  - Use the tokenizer
  - Optimize construction via the use of strings.Builder
- Modify the subScript function to return the raw script bytes since the
  parsed opcodes are no longer stored
- Update the various signature checking opcodes to use the raw opcode
  data removal and signature hash calculation functions since the
  subscript is now a raw script
  - opcodeCheckSig
  - opcodeCheckMultiSig
  - opcodeCheckSigAlt
2022-05-23 21:46:21 -07:00
Dave Collins
6198f45307 txscript: Convert to use non-parsed opcode disasm.
This converts the engine's current program counter disasembly to make
use of the standalone disassembly function to remove the dependency on
the parsed opcode struct.

It also updates the tests accordingly.
2022-05-23 21:46:21 -07:00
Dave Collins
07e1369839 txscript: Make min push accept raw opcode and data.
This converts the checkMinimalDataPush function defined on a parsed
opcode to a standalone function which accepts an opcode and data slice
instead in order to make it more flexible for raw script analysis.

It also updates all callers accordingly.
2022-05-23 21:46:21 -07:00
Dave Collins
e610deb203 txscript: Make isConditional accept raw opcode.
This converts the isConditional function defined on a parsed opcode to a
standalone function named isOpcodeConditional which accepts an opcode as
a byte instead in order to make it more flexible for raw script
analysis.

It also updates all callers accordingly.
2022-05-23 21:46:21 -07:00
Dave Collins
804327d22c txscript: Make alwaysIllegal accept raw opcode.
This converts the alwaysIllegal function defined on a parsed opcode to a
standalone function named isOpcodeAlwaysIllegal which accepts an opcode
as a byte instead in order to make it more flexible for raw script
analysis.

It also updates all callers accordingly.
2022-05-23 21:46:21 -07:00
Dave Collins
e928eeb5ce txscript: Make isDisabled accept raw opcode.
This converts the isDisabled function defined on a parsed opcode to a
standalone function which accepts an opcode as a byte instead in order
to make it more flexible for raw script analysis.

It also updates all callers accordingly.
2022-05-23 21:46:21 -07:00
Conner Fromknecht
25206b9565 txscript: Use removeOpcodeRaw for CODESEP in calcSigHash 2022-05-23 21:46:21 -07:00
Conner Fromknecht
1e3b85cd60 txscript: Remove unused removeOpcode 2022-05-23 21:46:21 -07:00
Conner Fromknecht
90b8c2cb51 txscript: Optimize removeOpcodeRaw 2022-05-23 21:46:21 -07:00
Dave Collins
f5d78e8b10 txscript: Implement efficient opcode data removal.
This introduces a new function named removeOpcodeByDataRaw which accepts
the raw scripts and data to remove versus requiring the parsed opcodes
to both significantly optimize it as well as make it more flexible for
working with raw scripts.

There are several places in the rest of the code that currently only
have access to the parsed opcodes, so this only introduces the function
for use in the future and deprecates the existing one.

Note that, in practice, the script will never actually contain the data
that is intended to be removed since the function is only used during
signature verification to remove the signature itself which would
require some incredibly non-standard code to create.

Thus, as an optimization, it avoids allocating a new script unless there
is actually a match that needs to be removed.

Finally, it updates the tests to use the new function.
2022-05-23 21:46:21 -07:00
Dave Collins
5283e30bfc txscript: Use raw scripts in SignTxOutput.
This converts SignTxOutput and supporting funcs, namely sign,
mergeScripts and mergeMultiSig, to make use of the new tokenizer as well
as some recently added funcs that deal with raw scripts in order to
remove the reliance on parsed opcodes as a step towards utlimately
removing them altogether and updates the comments to explicitly call out
the script version semantics.

It is worth noting that this has the side effect of optimizing the
function as well, however, since this change is not focused on the
optimization aspects, no benchmarks are provided.
2022-05-23 21:46:21 -07:00
Conner Fromknecht
b8e25c397c txscript: Use optimized calcWitnessSignatureHashRaw w/o parsing 2022-05-23 21:46:21 -07:00
Conner Fromknecht
21ed801540 txscript: Remove unused isWitnessPubKeyHash 2022-05-23 21:46:21 -07:00
Conner Fromknecht
13dbfa3d87 txscript: Introduce calcWitnessSignatureHashRaw 2022-05-23 21:46:21 -07:00
Dave Collins
f8978f5804 txscript: mergeMultiSig function def order cleanup.
This moves the function definition for mergeMultiSig so it is more
consistent with the preferred order used through the codebase.  In
particular, the functions are defined before they're first used and
generally as close as possible to the first use when they're defined in
the same file.
2022-05-23 21:46:21 -07:00
Conner Fromknecht
a3166c8d9b txscript: Optimize ExtractWitnessProgramInfo 2022-05-23 21:46:21 -07:00
Conner Fromknecht
ad01d080d9 txscript: Use internal analysis methods for GetWitnessSigOpCount 2022-05-23 21:46:21 -07:00
Conner Fromknecht
76131529f2 txscript: Return witness version and program in one pass 2022-05-23 21:46:21 -07:00
Conner Fromknecht
1936f28d33 txscript: Optimize IsWitnessProgram 2022-05-23 21:46:21 -07:00
Conner Fromknecht
67168099d3 txscript: Optimize ExtractPkScriptAddr assume non-standard if no success
This completes the process of converting the ExtractPkScriptAddr
function to use the optimized extraction functions recently introduced
as part of the typeOfScript conversion.

In particular, this cleans up the final remaining case for non-standard
transactions. The method now returns NonStandardTy direclty if no other
branch was taken.

The following is a before and after comparison of attempting to extract
pkscript addrs from a very large, non-standard script.

benchmark                                old ns/op     new ns/op     delta
BenchmarkExtractPkScriptAddrsLarge-8     60713         17.0          -99.97%
BenchmarkExtractPkScriptAddrs-8          289           17.0          -94.12%

benchmark                                old allocs     new allocs     delta
BenchmarkExtractPkScriptAddrsLarge-8     1              0              -100.00%
BenchmarkExtractPkScriptAddrs-8          1              0              -100.00%

benchmark                                old bytes     new bytes     delta
BenchmarkExtractPkScriptAddrsLarge-8     311299        0             -100.00%
BenchmarkExtractPkScriptAddrs-8          768           0             -100.00%
2022-05-23 21:46:21 -07:00
Conner Fromknecht
37f9cdd115 txscript: Optimize ExtractPkScriptAddrs witness script hash
This continues the process of converting the ExtractPkScriptAddrs
function to use the optimized extraction functions recently introduced
as part of the typeOfScript conversion.

In particular, this converts the extract of witness-pay-to-script-hash
scripts.
2022-05-23 21:46:21 -07:00
Conner Fromknecht
a3c39034b8 txscript: Optimize ExtractPkScriptAddrs witness pubkey hash
This continues the process of converting the ExtractPkScriptAddrs
function to use the optimized extraction functions recently introduced
as part of the typeOfScript conversion.

In particular, this converts the extraction for witness-pubkey-hash
scripts.
2022-05-23 21:46:21 -07:00
Dave Collins
45bdd26ac3 txscript: Optimize ExtractPkScriptAddrs nulldata.
This continues the process of converting the ExtractPkScriptAddrs
function to use the optimized extraction functions recently introduced
as part of the typeOfScript conversion.

In particular, this converts the detection for nulldata scripts, removes
the slow path fallback code since it is the final case, and modifies the
comment to call out the script version semantics.

The following is a before and after comparison of analyzing both a
typical standard script and a very large non-standard script:

benchmark                            old ns/op    new ns/op    delta
-----------------------------------------------------------------------
BenchmarkExtractPkScriptAddrsLarge   132400       44.4         -99.97%
BenchmarkExtractPkScriptAddrs        1265         231          -81.74%

benchmark                            old allocs   new allocs   delta
-----------------------------------------------------------------------
BenchmarkExtractPkScriptAddrsLarge   1            0            -100.00%
BenchmarkExtractPkScriptAddrs        5            2            -60.00%

benchmark                            old bytes    new bytes    delta
-----------------------------------------------------------------------
BenchmarkExtractPkScriptAddrsLarge   466944       0            -100.00%
BenchmarkExtractPkScriptAddrs        1600         48           -97.00%
2022-05-23 21:46:21 -07:00
Dave Collins
8a4da7690d txscript: Optimize ExtractPkScriptAddrs multisig.
This continues the process of converting the ExtractPkScriptAddrs
function to use the optimized extraction functions recently introduced
as part of the typeOfScript conversion.

In particular, this converts the detection for multisig scripts.

Also, since the remaining slow path cases are all recursive calls,
the parsed opcodes are no longer used, so parsing is removed.
2022-05-23 21:46:21 -07:00
Dave Collins
dcbff6a507 txscript: Optimize ExtractPkScriptAddrs pubkey.
This continues the process of converting the ExtractPkScriptAddrs
function to use the optimized extraction functions recently introduced
as part of the typeOfScript conversion.

In particular, this converts the detection for pay-to-pubkey scripts.
2022-05-23 21:46:21 -07:00
Dave Collins
9b541ad169 txscript: Optimize ExtractPkScriptAddrs pubkeyhash.
This continues the process of converting the ExtractPkScriptAddrs
function to use the optimized extraction functions recently introduced
as part of the typeOfScript conversion.

In particular, this converts the detection for pay-to-pubkey-hash
scripts.
2022-05-23 21:46:21 -07:00
Dave Collins
9dec01adf4 txscript: Optimize ExtractPkScriptAddrs scripthash.
This begins the process of converting the ExtractPkScriptAddrs function
to use the optimized extraction functions recently introduced as part of
the typeOfScript conversion.

In order to ease the review process, the detection of each script type
will be converted in a separate commit such that the script is only
parsed as a fallback for the cases that are not already converted to
more efficient variants.

In particular, this converts the detection for pay-to-script-hash
scripts.
2022-05-23 21:46:21 -07:00
Dave Collins
e4c9d283b5 txscript: Add ExtractPkScriptAddrs benchmarks. 2022-05-23 21:46:21 -07:00
Dave Collins
96c8bc1e93 txscript: Optimize ExtractAtomicSwapDataPushes.
This converts the ExtractAtomicSwapDataPushes function to make use of
the new tokenizer instead of the far less efficient parseScript thereby
significantly optimizing the function.

The new implementation is designed such that it should be fairly easy to
move the function into the atomic swap tools where it more naturally
belongs now that the tokenizer makes it possible to analyze scripts
outside of the txscript module.  Consequently, this also deprecates the
function.

The following is a before and after comparison of attempting to extract
from both a typical atomic swap script and a very large non-atomic swap
script:

benchmark                                       old ns/op     new ns/op     delta
BenchmarkExtractAtomicSwapDataPushesLarge-8     61332         44.4          -99.93%
BenchmarkExtractAtomicSwapDataPushes-8          990           260           -73.74%

benchmark                                       old allocs     new allocs     delta
BenchmarkExtractAtomicSwapDataPushesLarge-8     1              0              -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          2              1              -50.00%

benchmark                                       old bytes     new bytes     delta
BenchmarkExtractAtomicSwapDataPushesLarge-8     311299        0             -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          3168          96            -96.97%
2022-05-23 21:46:21 -07:00
Conner Fromknecht
767dae7adf txscript/scriptnum: add maxscriptnum and maxcltvlength 2022-05-23 21:46:21 -07:00
Dave Collins
76fcfbaa1f txscript: Add ExtractAtomicSwapDataPushes benches. 2022-05-23 21:46:21 -07:00
Dave Collins
ef4e561119 txscript: Make canonicalPush accept raw opcode.
This renames the canonicalPush function to isCanonicalPush and converts
it to accept an opcode as a byte and the associate data as a byte slice
instead of the internal parse opcode data struct in order to make it
more flexible for raw script analysis.

It also updates all callers and tests accordingly.
2022-05-23 21:46:21 -07:00
Dave Collins
afb68c4ea2 txscript: Optimize PushedData.
This converts the PushedData function to make use of the new tokenizer
instead of the far less efficient parseScript thereby significantly
optimizing the function.

Also, the comment is modified to explicitly call out the script version
semantics.

The following is a before and after comparison of extracting the data
from a very large script:

benchmark                 old ns/op     new ns/op     delta
BenchmarkPushedData-8     64837         1790          -97.24%

benchmark                 old allocs     new allocs     delta
BenchmarkPushedData-8     7              6              -14.29%

benchmark                 old bytes     new bytes     delta
BenchmarkPushedData-8     312816        1520          -99.51%
2022-05-23 21:46:21 -07:00
Dave Collins
e063742295 txscript: Add benchmark for PushedData. 2022-05-23 21:46:21 -07:00
Dave Collins
e0cafeb4ca txscript: Optimize CalcMultiSigStats.
This converts the CalcMultiSigStats function to make use of the new
extractMultisigScriptDetails function instead of the far less efficient
parseScript thereby significantly optimizing the function.

The tests are also updated accordingly.

The following is a before and after comparison of analyzing a standard
multisig script:

benchmark                    old ns/op    new ns/op    delta
---------------------------------------------------------------
BenchmarkCalcMultiSigStats   972          79.5         -91.82%

benchmark                    old allocs   new allocs   delta
---------------------------------------------------------------
BenchmarkCalcMultiSigStats   1            0            -100.00%

benchmark                    old bytes    new bytes    delta
---------------------------------------------------------------
BenchmarkCalcMultiSigStats   2304         0            -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
ea7b0e3816 txscript: Remove unused getSigOpCount function. 2022-05-23 21:46:21 -07:00
Dave Collins
e9a777d84e txscript: Remove unused isPushOnly function. 2022-05-23 21:46:21 -07:00
Dave Collins
ded9b8c506 txscript: Convert CalcScriptInfo.
This converts CalcScriptInfo and dependent expectedInputs to make use of
the new script tokenizer as well as several of the other recently added
raw script analysis functions in order to remove the reliance on parsed
opcodes as a step towards utlimately removing them altogether.

It is worth noting that this has the side effect of significantly
optimizing the function as well, however, since it is deprecated, no
benchmarks are provided.
2022-05-23 21:46:21 -07:00
Conner Fromknecht
0edfee87d6 txscript: Remove unused isWitnessScriptHash 2022-05-23 21:46:21 -07:00
Conner Fromknecht
6e0abb61bd txscript: Optimize typeOfScript for witness-script-hash
This concludes the process of converting the typeOfScript function to
use a combination of raw script analysis and the new tokenizer instead
of the far less efficient parsed opcodes.

In particular, it converts the detection of witness script hash scripts
to use raw script analysis and the new tokenizer.

With all of the limbs now useing optimized variants, the following is a
before an after comparison of calling GetScriptClass on a large script:

benchmark                     old ns/op     new ns/op     delta
BenchmarkGetScriptClass-8     61515         15.3          -99.98%

benchmark                     old allocs     new allocs     delta
BenchmarkGetScriptClass-8     1              0              -100.00%

benchmark                     old bytes     new bytes     delta
BenchmarkGetScriptClass-8     311299        0             -100.00%
2022-05-23 21:46:21 -07:00
Conner Fromknecht
918278a251 txscript: Optimize typeOfScript witness-pubkey-hash
This continues the process of converting the typeOfScript function to
use a combination of raw script analysis and the new tokenizer instead
of the far less efficient parsed opcodes.

In particular, it converts the detection of witness pubkey hash scripts
to use raw script analysis and the new tokenizer.

The following is a before and after comparison of analyzing a large
script:

benchmark                          old ns/op     new ns/op     delta
BenchmarkIsWitnessPubKeyHash-8     61688         62839         +1.87%

benchmark                          old allocs     new allocs     delta
BenchmarkIsWitnessPubKeyHash-8     1              1              +0.00%

benchmark                          old bytes     new bytes     delta
BenchmarkIsWitnessPubKeyHash-8     311299        311299        +0.00%
2022-05-23 21:46:21 -07:00
Dave Collins
9cfaf49024 txscript: Remove unused isNullData function. 2022-05-23 21:46:21 -07:00
Conner Fromknecht
b5e58f4a8d txscript: Optimize typeOfScript for null data scripts
This continues the process of converting the typeOfScript function to
use a combination of raw script analysize and the tokenizer instead of
parsed opcode, with the intent of significanty optimizing the function.

In particular, it converts the detection of null data scripts to use raw
script analysis.
2022-05-23 21:46:21 -07:00
Dave Collins
461335437a txscript: Remove unused isPubkeyHash function. 2022-05-23 21:46:21 -07:00
Dave Collins
c52f41a5af txscript: Optimize typeOfScript pay-to-pubkey-hash.
This continues the process of converting the typeOfScript function to
use a combination of raw script analysis and the new tokenizer instead
of the far less efficient parsed opcodes.

In particular, it converts the detection of pay-to-pubkey-hash scripts
to use raw script analysis.
2022-05-23 21:46:21 -07:00
Dave Collins
cb4018a1d4 txscript: Remove unused isPubkey function. 2022-05-23 21:46:21 -07:00
Conner Fromknecht
b1544cd4a9 txscript: Optimze typeOfScript pay-to-pubkey
This continues the process of converting the typeOfScript function to
use a combination of raw script analysis and the new tokenizer instead
of the face less efficient parsed opcodes, with the intent of
significantly optimizing the function.

In particular, it converts the detection of pay-to-pubkey scripts to use
raw script analysis.
2022-05-23 21:46:21 -07:00
Dave Collins
1f25921172 txscript: Remove unused isMultiSig function. 2022-05-23 21:46:21 -07:00
Dave Collins
cfb6bc9399 txscript: Optimize typeOfScript multisig.
This continues the process of converting the typeOfScript function to
use a combination of raw script analysis and the new tokenizer instead
of the far less efficient parsed opcodes.

In particular, for this commit, since the ability to detect multisig
scripts via the new tokenizer is now available, the function is simply
updated to make use of it.
2022-05-23 21:46:21 -07:00
Dave Collins
c85458bc7c txscript: Remove unused isScriptHash function. 2022-05-23 21:46:21 -07:00
Dave Collins
603c2e3b2b txscript: Optimize typeOfScript pay-to-script-hash.
This begins the process of converting the typeOfScript function to use a
combination of raw script analysis and the new tokenizer instead of the
far less efficient parsed opcodes with the intent of significantly
optimizing the function.

In order to ease the review process, each script type will be converted
in a separate commit and the typeOfScript function will be updated such
that the script is only parsed as a fallback for the cases that are not
already converted to more efficient raw script variants.

In particular, for this commit, since the ability to detect
pay-to-script-hash via raw script analysis is now available, the
function is simply updated to make use of it.
2022-05-23 21:46:21 -07:00
Dave Collins
9ac8abd519 txscript: Make typeOfScript accept raw script.
This converts the typeOfScript function to accept a script version and
raw script instead of an array of internal parsed opcodes in order to
make it more flexible for raw script analysis.

Also, this adds a comment to CalcScriptInfo to call out the specific
version semantics and deprecates the function since nothing currently
uses it, and the relevant information can now be obtained by callers
more directly through the use of the new script tokenizer.

All other callers are updated accordingly.
2022-05-23 21:46:21 -07:00
Dave Collins
aa5a1d1648 txscript: Add benchmark for GetScriptClass. 2022-05-23 21:46:21 -07:00
Conner Fromknecht
43e2a2acb2 txscript: Optimize GetWitnessSigOpCount
This converts the GetWitnessSigOpCount function to use a combination of
raw script analysis and the new tokenizer instead of the far less
efficeint parseScript, thereby significantly optimizing the funciton.

In particular, it use the recently added countSigOpsv0 in precise mode
to avoid calling paseScript.
2022-05-23 21:46:21 -07:00
Conner Fromknecht
83442d60bf txscript: add GetWitnessSigOpCountBenchmarks 2022-05-23 21:46:21 -07:00
Dave Collins
b607be0852 txscript: Optimize GetPreciseSigOpCount.
This converts the GetPreciseSigOpCount function to use a combination of
raw script analysis and the new tokenizer instead of the far less
efficient parseScript thereby significantly optimizing the function.

In particular it uses the recently converted isScriptHashScript,
IsPushOnlyScript, and countSigOpsV0 functions along with the recently
added finalOpcodeData functions.

It also modifies the comment to explicitly call out the script version
semantics.

The following is a before and after comparison of analyzing a large
script:

benchmark                           old ns/op     new ns/op     delta
BenchmarkGetPreciseSigOpCount-8     130223        742           -99.43%

benchmark                           old allocs     new allocs     delta
BenchmarkGetPreciseSigOpCount-8     3              0              -100.00%

benchmark                           old bytes     new bytes     delta
BenchmarkGetPreciseSigOpCount-8     623367        0             -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
8de1bc3ecc txscript: Add benchmark for GetPreciseSigOpCount. 2022-05-23 21:46:21 -07:00
Dave Collins
873339c5bc txscript: Optimize GetSigOpCount.
This converts the GetSigOpCount function to make use of the new
tokenizer instead of the far less efficient parseScript thereby
significantly optimizing the function.

A new function named countSigOpsV0 which accepts the raw script is
introduced to perform the bulk of the work so it can be reused for
precise signature operation counting as well in a later commit.  It
retains the same semantics in terms of counting the number of signature
operations either up to the first parse error or the end of the script
in the case it parses successfully as required by consensus.

Finally, this also deprecates the getSigOpCount function that requires
opcodes in favor of the new function and modifies the comment on
GetSigOpCount to explicitly call out the script version semantics.

The following is a before and after comparison of analyzing a large
script:

benchmark                    old ns/op     new ns/op     delta
BenchmarkGetSigOpCount-8     61051         677           -98.89%

benchmark                    old allocs     new allocs     delta
BenchmarkGetSigOpCount-8     1              0              -100.00%

benchmark                    old bytes     new bytes     delta
BenchmarkGetSigOpCount-8     311299        0             -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
c7218b2622 txscript: Add benchmark for GetSigOpCount. 2022-05-23 21:46:21 -07:00
Conner Fromknecht
f1ab6cc7cb txscript/engine: Check ps2h push before parsing script
This moves the check for non push-only pay-to-script-hash signature
scripts before the script parsing logic when creating a new engine
instance to avoid the extra overhead in the error case.
2022-05-23 21:46:21 -07:00
Conner Fromknecht
2674b2926b txscript/engine: Use optimized isScriptHashScript 2022-05-23 21:46:21 -07:00
Conner Fromknecht
c0b2b10241 txscript/engine: Use optimized IsPushOnlyScript 2022-05-23 21:46:21 -07:00
Conner Fromknecht
1814b48565 txscript/engine: Optimize new engine push only script
This modifies the check for whether or not a pay-to-script-hash
signature script is a push only script to make use of the new and more
efficient raw script function.

Also, since the script will have already been checked further above when
the ScriptVerifySigPushOnly flags is set, avoid checking it again in
that case.

Backport of af67951b9a66df3aac1bf3d6376af0730287bbf2
2022-05-23 21:46:21 -07:00
Dave Collins
814f0bae89 txscript: Optimize IsUnspendable.
This converts the IsUnspendable function to make use of a combination of
raw script analysis and the new tokenizer instead of the far less
efficient parseScript thereby significantly optimizing the function.

It is important to note that this new implementation intentionally has a
semantic difference from the existing implementation in that it will now
report scripts that are larger than the max allowed script size are
unspendable as well.

Finally, the comment is modified to explicitly call out the script
version semantics.

Note: this function was recently optimized in master, so the gains here
are less noticable than other optimizations.

The following is a before and after comparison of analyzing a large
script:

benchmark                    old ns/op     new ns/op     delta
BenchmarkIsUnspendable-8     656           584           -10.98%

benchmark                    old allocs     new allocs     delta
BenchmarkIsUnspendable-8     1              0              -100.00%

benchmark                    old bytes     new bytes     delta
BenchmarkIsUnspendable-8     1             0             -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
90e7a42585 txscript: Add benchmark for IsUnspendable. 2022-05-23 21:46:21 -07:00
Conner Fromknecht
b4f144ad8c txscript: Optimize IsNullData
This converts the IsNullData function to analyze the raw script instead
of using the far less efficient parseScript, thereby significantly
optimizing the function.

The following is a before and after comparison of analyzing a large
script:

benchmark                       old ns/op     new ns/op     delta
BenchmarkIsNullDataScript-8     62495         2.65          -100.00%

benchmark                       old allocs     new allocs     delta
BenchmarkIsNullDataScript-8     1              0              -100.00%

benchmark                       old bytes     new bytes     delta
BenchmarkIsNullDataScript-8     311299        0             -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
4878db49cf txscript: Add benchmark for IsNullData 2022-05-23 21:46:21 -07:00
Conner Fromknecht
44c6be3d4e txscript: Optimize IsPayToWitnessScriptHash
This converts the IsPayToWitnessScriptHash function to analyze the raw
script instead of using the far less efficient parseScript, thereby
significantly optimizing the function.

In order to accomplish this, it introduces two new functions. The first
one is named extractWitnessScriptHash and works with the raw script byte
to simultaneously deteremine if the script is a p2wsh script, and in the
case that is is, extract and return the hash. The second new function is
named isWitnessScriptHashScript and is defined in terms of the former.

The extract function approach was chosed because it is common for
callers to want to only extract relevant details from a script if the
script is of the specific type. Extracting those details requires
performing the exact same checks to ensure the script is of the correct
type, so it is more efficient to combine the two into one and define the
type determination in terms of the result, so long as the extraction
does not require allocations.

Finally, this also deprecates the isWitnessScriptHash function that
requires opcodes in favor of the new functions and modifies the comment
on IsPayToWitnessScriptHash to call out the script version semantics.

The following is a before and after comparison of executing
IsPayToWitnessScriptHash on a large script:

benchmark                          old ns/op     new ns/op     delta
BenchmarkIsWitnessScriptHash-8     62774         0.63          -100.00%

benchmark                          old allocs     new allocs     delta
BenchmarkIsWitnessScriptHash-8     1              0              -100.00%

benchmark                          old bytes     new bytes     delta
BenchmarkIsWitnessScriptHash-8     311299        0             -100.00%
2022-05-23 21:46:21 -07:00
Conner Fromknecht
b3dd941a77 txscript: Add benchmark for IsPayToWitnessScriptHash 2022-05-23 21:46:21 -07:00
Conner Fromknecht
4d8edfe6d9 txscript: Optimize IsPayToWitnessPubKeyHash
This converts the IsPayToWitnessPubKeyHash function to analyze the raw
script instead of the far less efficient parseScript, thereby
significantly optimizing the function.

In order to accomplish this, it introduces two new functions. The first
one is named extractWitnessPubKeyHash and works with the raw script
bytes to simultaneously deteremine if the script is a p2wkh, and in case
it is, extract and return the hash. The second new function is name
isWitnessPubKeyHashScript which is defined in terms of the former.

The extract function is approach was chosen because it is common for
callers to want to only extract relevant details from the script if the
script is of the specific type. Extracting those details requires the
exact same checks to ensure the script is of the correct type, so it is
more efficient to combine the two and define the type determination in
terms of the result so long as the extraction does not require
allocations.

Finally, this deprecates the isWitnessPubKeyHash function that requires
opcodes in favor of the new functions and modifies the comment on
IsPayToWitnessPubKeyHash to explicitly call out the script version
semantics.

The following is a before and after comparison of executing
IsPayToWitnessPubKeyHash on a large script:

benchmark                          old ns/op     new ns/op     delta
BenchmarkIsWitnessPubKeyHash-8     68927         0.53          -100.00%

benchmark                          old allocs     new allocs     delta
BenchmarkIsWitnessPubKeyHash-8     1              0              -100.00%

benchmark                          old bytes     new bytes     delta
BenchmarkIsWitnessPubKeyHash-8     311299        0             -100.00%
2022-05-23 21:46:21 -07:00
Conner Fromknecht
38ade2c48f txscript: Add benchmark IsPayToWitnessPubkeyHash 2022-05-23 21:46:21 -07:00
Dave Collins
02ddaf29fd txscript: Optimize IsPushOnlyScript.
This converts the IsPushOnlyScript function to make use of the new
tokenizer instead of the far less efficient parseScript thereby
significantly optimizing the function.

It also deprecates the isPushOnly function that requires opcodes in
favor of the new function and modifies the comment on IsPushOnlyScript
to explicitly call out the script version semantics.

The following is a before and after comparison of analyzing a large
script:

benchmark                       old ns/op     new ns/op     delta
BenchmarkIsPushOnlyScript-8     62412         622           -99.00%

benchmark                       old allocs     new allocs     delta
BenchmarkIsPushOnlyScript-8     1              0              -100.00%

benchmark                       old bytes     new bytes     delta
BenchmarkIsPushOnlyScript-8     311299        0             -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
2b5edd2b5e txscript: Add benchmark for IsPushOnlyScript. 2022-05-23 21:46:21 -07:00
Dave Collins
6be04a8e43 txscript: Optimize IsMultisigSigScript.
This converts the IsMultisigSigScript function to analyze the raw script
and make use of the new tokenizer instead of the far less efficient
parseScript thereby significantly optimizing the function.

In order to accomplish this, it first rejects scripts that can't
possibly fit the bill due to the final byte of what would be the redeem
script not being the appropriate opcode or the overall script not having
enough bytes.  Then, it uses a new function that is introduced named
finalOpcodeData that uses the tokenizer to return any data associated
with the final opcode in the signature script (which will be nil for
non-push opcodes or if the script fails to parse) and analyzes it as if
it were a redeem script when it is non nil.

It is also worth noting that this new implementation intentionally has
the same semantic difference from the existing implementation as the
updated IsMultisigScript function in regards to allowing zero pubkeys
whereas previously it incorrectly required at least one pubkey.

Finally, the comment is modified to explicitly call out the script
version semantics.

The following is a before and after comparison of analyzing a large
script that is not a multisig script and both a 1-of-2 multisig public
key script (which should be false) and a signature script comprised of a
pay-to-script-hash 1-of-2 multisig redeem script (which should be true):

benchmark                               old ns/op     new ns/op     delta
BenchmarkIsMultisigSigScriptLarge-8     69328         2.93          -100.00%
BenchmarkIsMultisigSigScript-8          2375          146           -93.85%

benchmark                               old allocs     new allocs     delta
BenchmarkIsMultisigSigScriptLarge-8     5              0              -100.00%
BenchmarkIsMultisigSigScript-8          3              0              -100.00%

benchmark                               old bytes     new bytes     delta
BenchmarkIsMultisigSigScriptLarge-8     330035        0             -100.00%
BenchmarkIsMultisigSigScript-8          9472          0             -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
3bdeaa46bf txscript: Add benchmarks for IsMutlsigSigScript. 2022-05-23 21:46:21 -07:00
Dave Collins
67e2cbe374 txscript: Optimize IsMultisigScript.
This converts the IsMultisigScript function to make use of the new
tokenizer instead of the far less efficient parseScript thereby
significantly optimizing the function.

In order to accomplish this, it introduces two new functions.  The first
one is named extractMultisigScriptDetails and works with the raw script
bytes to simultaneously determine if the script is a multisignature
script, and in the case it is, extract and return the relevant details.
The second new function is named isMultisigScript and is defined in
terms of the former.

The extract function accepts the script version, raw script bytes, and a
flag to determine whether or not the public keys should also be
extracted.  The flag is provided because extracting pubkeys results in
an allocation that the caller might wish to avoid.

The extract function approach was chosen because it is common for
callers to want to only extract relevant details from a script if the
script is of the specific type.  Extracting those details requires
performing the exact same checks to ensure the script is of the correct
type, so it is more efficient to combine the two into one and define the
type determination in terms of the result so long as the extraction does
not require allocations.

It is important to note that this new implementation intentionally has a
semantic difference from the existing implementation in that it will now
correctly identify a multisig script with zero pubkeys whereas
previously it incorrectly required at least one pubkey.  This change is
acceptable because the function only deals with standardness rather than
consensus rules.

Finally, this also deprecates the isMultiSig function that requires
opcodes in favor of the new functions and deprecates the error return on
the export IsMultisigScript function since it really does not make sense
given the purpose of the function.

The following is a before and after comparison of analyzing both a large
script that is not a multisig script and a 1-of-2 multisig public key
script:

benchmark                            old ns/op     new ns/op     delta
BenchmarkIsMultisigScriptLarge-8     64166         5.52          -99.99%
BenchmarkIsMultisigScript-8          630           59.4          -90.57%

benchmark                            old allocs     new allocs     delta
BenchmarkIsMultisigScriptLarge-8     1              0              -100.00%
BenchmarkIsMultisigScript-8          1              0              -100.00%

benchmark                            old bytes     new bytes     delta
BenchmarkIsMultisigScriptLarge-8     311299        0             -100.00%
BenchmarkIsMultisigScript-8          2304          0             -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
a6244b516d txscript: Add benchmarks for IsMutlsigScript. 2022-05-23 21:46:21 -07:00
Dave Collins
69aefa65e6 txscript: Optimize IsPayToScriptHash.
This converts the IsPayToScriptHash function to analyze the raw script
instead of using the far less efficient parseScript thereby
significantly optimizing the function.

In order to accomplish this, it introduces two new functions.  The first
one is named extractScriptHash and works with the raw script bytes to
simultaneously determine if the script is a p2sh script, and in the case
it is, extract and return the hash.  The second new function is named
isScriptHashScript and is defined in terms of the former.

The extract function approach was chosen because it is common for
callers to want to only extract relevant details from a script if the
script is of the specific type.  Extracting those details requires
performing the exact same checks to ensure the script is of the correct
type, so it is more efficient to combine the two into one and define the
type determination in terms of the result so long as the extraction does
not require allocations.

Finally, this also deprecates the isScriptHash function that requires
opcodes in favor of the new functions and modifies the comment on
IsPayToScriptHash to explicitly call out the script version semantics.

The following is a before and after comparison of analyzing a large
script that is not a p2sh script:

benchmark                        old ns/op     new ns/op     delta
BenchmarkIsPayToScriptHash-8     62393         0.60          -100.00%

benchmark                        old allocs     new allocs     delta
BenchmarkIsPayToScriptHash-8     1              0              -100.00%

benchmark                        old bytes     new bytes     delta
BenchmarkIsPayToScriptHash-8     311299        0             -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
e7228a2e5f txscript: Add benchmark for IsPayToScriptHash. 2022-05-23 21:46:21 -07:00
Conner Fromknecht
eb03d84098 txscript: Optimize IsPayToPubKeyHash
This converts the IsPayToPubKeyHash function to analyze the raw script
instead of using the far less efficient parseScript, thereby
significantly optimization the function.

In order to accomplish this, it introduces two new functions.  The first
one is named extractPubKeyHash and works with the raw script bytes
to simultaneously determine if the script is a pay-to-pubkey-hash script,
and in the case it is, extract and return the hash.  The second new
function is named isPubKeyHashScript and is defined in terms of the
former.

The extract function approach was chosen because it is common for
callers to want to only extract relevant details from a script if the
script is of the specific type.  Extracting those details requires
performing the exact same checks to ensure the script is of the correct
type, so it is more efficient to combine the two into one and define the
type determination in terms of the result so long as the extraction does
not require allocations.

The following is a before and after comparison of analyzing a large
script:

benchmark                         old ns/op     new ns/op     delta
BenchmarkIsPubKeyHashScript-8     62228         0.45          -100.00%

benchmark                         old allocs     new allocs     delta
BenchmarkIsPubKeyHashScript-8     1              0              -100.00%

benchmark                         old bytes     new bytes     delta
BenchmarkIsPubKeyHashScript-8     311299        0             -100.00%
2022-05-23 21:46:21 -07:00
Conner Fromknecht
c4da180d4f txscript: Add benchmark for IsPayToPubKeyHash 2022-05-23 21:46:21 -07:00
Conner Fromknecht
5d18558bc6 txscript: Optimize IsPayToPubKey
This converts the IsPayToScriptHash function to analyze the raw script
instead of using the far less efficient parseScript, thereby
significantly optimizing the function.

In order to accomplish this, it introduces four new functions:
extractCompressedPubKey, extractUncompressedPubKey, extractPubKey, and
isPubKeyScript.  The extractPubKey function makes use of
extractCompressedPubKey and extractUncompressedPubKey to combine their
functionality as a convenience and isPubKeyScript is defined in terms of
extractPubKey.

The extractCompressedPubKey works with the raw script bytes to
simultaneously determine if the script is a pay-to-compressed-pubkey
script, and in the case it is, extract and return the raw compressed
pubkey bytes.

Similarly, the extractUncompressedPubKey works in the same way except it
determines if the script is a pay-to-uncompressed-pubkey script and
returns the raw uncompressed pubkey bytes in the case it is.

The extract function approach was chosen because it is common for
callers to want to only extract relevant details from a script if the
script is of the specific type.  Extracting those details requires
performing the exact same checks to ensure the script is of the correct
type, so it is more efficient to combine the two into one and define the
type determination in terms of the result so long as the extraction does
not require allocations.

The following is a before and after comparison of analyzing a large
script:

benchmark                     old ns/op     new ns/op     delta
BenchmarkIsPubKeyScript-8     62323         2.97          -100.00%

benchmark                     old allocs     new allocs     delta
BenchmarkIsPubKeyScript-8     1              0              -100.00%

benchmark                     old bytes     new bytes     delta
BenchmarkIsPubKeyScript-8     311299        0             -100.00%
2022-05-23 21:46:21 -07:00
Dave Collins
28eaf3492d txscript: Add benchmark for IsPayToPubKey 2022-05-23 21:46:21 -07:00
Dave Collins
8c68575331 txscript: Make asSmallInt accept raw opcode.
This converts the asSmallInt function to accept an opcode as a byte
instead of the internal opcode data struct in order to make it more
flexible for raw script analysis.

It also updates all callers accordingly.
2022-05-23 21:46:21 -07:00
Dave Collins
45de22d457 txscript: Make isSmallInt accept raw opcode.
This converts the isSmallInt function to accept an opcode as a byte
instead of the internal opcode data struct in order to make it more
flexible for raw script analysis.

The comment is modified to explicitly call out the script version
semantics.

Finally, it updates all callers accordingly.
2022-05-23 21:46:21 -07:00
Conner Fromknecht
a02b71bcf9 txscript/reference_test: Convert sighash calc test
This converts the tests for calculating signature hashes to use the
exported function which handles the raw script versus the now deprecated
variant requiring parsed opcodes.

Backport of 06f769ef72e6042e7f2b5ff1c512ef1371d615e5
2022-05-23 21:46:21 -07:00
Dave Collins
18aa1a59df txscript: Optimize CalcSignatureHash.
This modifies the CalcSignatureHash function to make use of the new
signature hash calculation function that accepts raw scripts without
needing to first parse them.  Consequently, it also doubles as a slight
optimization to the execution time and a significant reduction in the
number of allocations.

In order to convert the CalcScriptHash function and keep the same
semantics, a new function named checkScriptParses is introduced which
will quickly determine if a script can be fully parsed without failure
and return the parse failure in the case it can't.

The following is a before and after comparison of analyzing a large
multiple input transaction:

benchmark                  old ns/op     new ns/op     delta
BenchmarkCalcSigHash-8     3627895       3619477       -0.23%

benchmark                  old allocs     new allocs     delta
BenchmarkCalcSigHash-8     1335           801            -40.00%

benchmark                  old bytes     new bytes     delta
BenchmarkCalcSigHash-8     1373812       1293354       -5.86%
2022-05-23 21:46:21 -07:00
Conner Fromknecht
07c1a9343d txscript: Introduce raw script sighash calc func.
This introduces a new function named calcSignatureHashRaw which accepts
the raw script bytes to calculate the script hash versus requiring the
parsed opcode only to unparse them later in order to make it more
flexible for working with raw scripts.

Since there are several places in the rest of the code that currently
only have access to the parsed opcodes, this modifies the existing
calcSignatureHash to first unparse the script before calling the new
function.

Backport of decred/dcrd:f306a72a16eaabfb7054a26f9d9f850b87b00279
2022-05-23 21:46:21 -07:00
Dave Collins
ce08988514 txscript: Optimize script disasm.
This converts the DisasmString function to make use of the new
zero-allocation script tokenizer instead of the far less efficient
parseScript thereby significantly optimizing the function.

In order to facilitate this, the opcode disassembly functionality is
split into a separate function called disasmOpcode that accepts the
opcode struct and data independently as opposed to requiring a parsed
opcode.  The new function also accepts a pointer to a string builder so
the disassembly can be more efficiently be built.

While here, the comment is modified to explicitly call out the script
version semantics.

The following is a before and after comparison of a large script:

benchmark                   old ns/op     new ns/op     delta
BenchmarkDisasmString-8     102902        40124         -61.01%

benchmark                   old allocs     new allocs     delta
BenchmarkDisasmString-8     46             51             +10.87%

benchmark                   old bytes     new bytes     delta
BenchmarkDisasmString-8     389324        130552        -66.47%
2022-05-23 21:46:20 -07:00
Dave Collins
94bb41664b txscript: Add benchmark for DisasmString. 2022-05-23 21:46:20 -07:00
Dave Collins
ac002d6422 txscript: Introduce zero-alloc script tokenizer.
This implements an efficient and zero-allocation script tokenizer that
is exported to both provide a new capability to tokenize scripts to
external consumers of the API as well as to serve as a base for
refactoring the existing highly inefficient internal code.

It is important to note that this tokenizer is intended to be used in
consensus critical code in the future, so it must exactly follow the
existing semantics.

The current script parsing mechanism used throughout the txscript module
is to fully tokenize the scripts into an array of internal parsed
opcodes which are then examined and passed around in order to implement
virtually everything related to scripts.

While that approach does simplify the analysis of certain scripts and
thus provide some nice properties in that regard, it is both extremely
inefficient in many cases, and makes it impossible for external
consumers of the API to implement any form of custom script analysis
without manually implementing a bunch of error prone tokenizing code or,
alternatively, the script engine exposing internal structures.

For example, as shown by profiling the total memory allocations of an
initial sync, the existing script parsing code allocates a total of
around 295.12GB, which equates to around 50% of all allocations
performed.  The zero-alloc tokenizer this introduces will allow that to
be reduced to virtually zero.

The following is a before and after comparison of tokenizing a large
script with a high opcode count using the existing code versus the
tokenizer this introduces for both speed and memory allocations:

benchmark                    old ns/op     new ns/op     delta
BenchmarkScriptParsing-8     63464         677           -98.93%

benchmark                    old allocs     new allocs     delta
BenchmarkScriptParsing-8     1              0              -100.00%

benchmark                    old bytes     new bytes     delta
BenchmarkScriptParsing-8     311299        0             -100.00%

The following is an overview of the changes:

- Introduce new error code ErrUnsupportedScriptVersion
- Implement zero-allocation script tokenizer
- Add a full suite of tests to ensure the tokenizer works as intended
  and follows the required consensus semantics
- Add an example of using the new tokenizer to count the number of
  opcodes in a script
- Update README.md to include the new example
- Update script parsing benchmark to use the new tokenizer
2022-05-23 21:46:20 -07:00
Dave Collins
fc5b1a817c txscript: Add benchmark for script parsing. 2022-05-23 21:46:20 -07:00
Conner Fromknecht
b2784102f4 txscript: Add benchmark for CalcWitnessSigHash 2022-05-23 21:46:20 -07:00
Dave Collins
42f4b4025c txscript: Add benchmark for CalcSignatureHash 2022-05-23 21:46:20 -07:00
3nprob
cc7327c194 rpcclient: Add retry with backoffs to HTTP POST requests
Adds behavior similar to the retries of persistent RPC connections
to HTTP request.

* Initial backoff: 500ms
* Linear increase
* Max retries: 10

Room for future improvement:
* Make configurable
* Add jitter
* Tests for retry behavior
2021-11-16 09:08:07 -05:00
Aarush Bhat
65e986844e Update connmanager_test.go 2021-11-10 07:59:03 -05:00
naveen
31791ba4dc Included permissions for GitHub action
The default GitHub Action is write which is not required for this
action.
2021-10-26 10:00:04 -04:00
pengyonghui
c56a053fdf fix typos 2021-10-26 09:56:57 -04:00
pengyonghui
d590f3f77d fix typo 2021-10-26 09:56:57 -04:00
Jonathan Chappelow
a148fa797a addrmgr: make KnownAddress methods thread-safe
This gives KnownAddress a sync.RWMutex so the exported methods may
safely access the na (*wire.NetAddress) and lastattempt fields.
The AddrManager is updated to lock the new KnownAddress mutex before
assigning to na or lastattempt.
The other KnownAddress fields are only accessed by AddrManager, using
its own Mutex for synchronization.
2021-10-26 09:55:49 -04:00
Olaoluwa Osuntokun
e3449998be
Merge pull request #1752 from Roasbeef/config-disable-stall-handler
peer+server: add new config option to optionally disable stall detection
2021-10-05 11:44:31 -07:00
Olaoluwa Osuntokun
e98a1a1b4c
peer+server: add new config option to optionally disable stall detection
In this commit, we add a new config options that allows one to start
`btcd` in an operating mode that disables the stall detection. This can
be useful in simnet/regtest integration tests settings where it's
important that `btcd` holds on to its possibly sole connection to the
only other node in the test harness.

A new config flag has been added to gate this behavior, which is off by
default.
2021-10-01 14:55:50 -07:00
naveen
4caf037c52 Upgraded the docker version to 1.16
With this changes https://github.com/btcsuite/btcd/pull/1753/ merged in
the docker image also has to be upgraded.
2021-09-17 11:17:29 -04:00
Olaoluwa Osuntokun
bca4298ada
Merge pull request #1753 from Roasbeef/bump-go-version
build: bump min Go version to 1.16.8 add Go 1.17.1
2021-09-16 14:32:45 -07:00
eugene
f8e6854197 mempool: introduce GetDustThreshold to export dust limit calculation
This commit modifies no behavior and would allow other projects to
retrieve the dust limit for a particular output type before the
amount of the output is known. This is particularly useful in the
Lightning Network for channel negotiation.
2021-09-16 15:17:17 -04:00
Olaoluwa Osuntokun
7ae5b74dee
build: bump min Go version to 1.16.8 add Go 1.17.1 2021-09-15 18:19:34 -07:00
Marius van der Wijden
5e6736aad5 btcec: added testcase for point at infinity 2021-09-13 15:59:28 -04:00
Marius van der Wijden
73f7eac903 btcec: check if recovered pk is at point of infinity 2021-09-13 15:59:28 -04:00
JeremyRand
3e2d8464f1
rpcclient: Export symbols needed for custom commands (#1457)
* rpcclient: Export sendCmd and response

This facilitates using custom commands with rpcclient.

See https://github.com/btcsuite/btcd/issues/1083

* rpcclient: Export receiveFuture

This facilitates using custom commands with rpcclient.

See https://github.com/btcsuite/btcd/issues/1083

* rpcclient: Add customcommand example

* rpcclient: remove "Namecoin" from customcommand readme heading
2021-09-02 08:39:55 +02:00
John C. Vernaleo
f9d72f05a4 Switch irc to libera.chat 2021-08-31 07:50:29 -04:00
eugene
f5a1fb9965 mempool: export isDust for use in other projects
This changes isDust to IsDust so other golang projects (btcwallet
or lnd) can use the precise dust calculation used by btcd.
2021-08-03 09:34:49 -04:00
Calvin Kim
b3e6bd6161 rpcserverhelp: Remove extra period for gettxout--synopsis 2021-07-27 10:27:50 -04:00
Anirudha Bose
86a17263b0
Merge pull request #1729 from gnasr/fix-psbtopts-feerate-type
btcjson: Update WalletCreateFundedPsbtOpts.FeeRate type
2021-06-25 21:49:46 +02:00
Gabriel Nasr
505915dc3f btcjson: Update WalletCreateFundedPsbtOpts.FeeRate from *int64 to *float64 2021-06-25 15:23:44 -03:00
412 changed files with 44890 additions and 13122 deletions

View file

@ -2,27 +2,27 @@ name: Build and Test
on: [push, pull_request]
jobs:
build:
# https://github.blog/changelog/2021-04-20-github-actions-control-permissions-for-github_token/
permissions:
contents: read
name: Go CI
runs-on: ubuntu-latest
strategy:
matrix:
go: [1.14, 1.15]
go: [1.19]
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Check out source
uses: actions/checkout@v2
- name: Install Linters
run: "curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.26.0"
- name: Build
env:
GO111MODULE: "on"
run: go build ./...
- name: Test
env:
GO111MODULE: "on"
run: |
sh ./goclean.sh

35
.github/workflows/full-sync-part-1.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: Full Sync From 0
on:
workflow_dispatch:
inputs:
note:
description: 'Note'
required: false
default: ''
jobs:
build:
name: Go CI
runs-on: self-hosted
strategy:
matrix:
go: [1.19]
steps:
- run: |
echo "Note ${{ github.event.inputs.note }}!"
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Checkout source
uses: actions/checkout@v2
- name: Build lbcd
run: go build .
- name: Create datadir
run: echo "TEMP_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV
- name: Run lbcd
run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --nolisten --norpc
- name: Remove datadir
if: always()
run: rm -rf ${{env.TEMP_DATA_DIR}}

37
.github/workflows/full-sync-part-2.yml vendored Normal file
View file

@ -0,0 +1,37 @@
name: Full Sync From 814k
on:
workflow_dispatch:
inputs:
note:
description: 'Note'
required: false
default: ''
jobs:
build:
name: Go CI
runs-on: self-hosted
strategy:
matrix:
go: [1.19]
steps:
- run: |
echo "Note ${{ github.event.inputs.note }}!"
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Checkout source
uses: actions/checkout@v2
- name: Build lbcd
run: go build .
- name: Create datadir
run: echo "TEMP_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV
- name: Copy initial data
run: cp -r /home/lbry/lbcd_814k/* ${{env.TEMP_DATA_DIR}}
- name: Run lbcd
run: ./lbcd --datadir=${{env.TEMP_DATA_DIR}}/data --logdir=${{env.TEMP_DATA_DIR}}/logs --nolisten --norpc
- name: Remove datadir
if: always()
run: rm -rf ${{env.TEMP_DATA_DIR}}

57
.github/workflows/golangci-lint.yml vendored Normal file
View file

@ -0,0 +1,57 @@
name: golangci-lint
env:
# go needs absolute directories, using the $HOME variable doesn't work here.
GOCACHE: /home/runner/work/go/pkg/build
GOPATH: /home/runner/work/go
GO_VERSION: '^1.19'
on:
push:
tags:
- v*
branches:
- "*"
pull_request:
branches:
- "*"
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- name: setup go ${{ env.GO_VERSION }}
uses: actions/setup-go@v2
with:
go-version: '${{ env.GO_VERSION }}'
- name: checkout source
uses: actions/checkout@v2
- name: compile code
run: go install -v ./...
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: latest
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true
# Optional: if set to true then the action will use pre-installed Go.
skip-go-installation: true
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
# skip-pkg-cache: true
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true

57
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,57 @@
name: goreleaser
on:
workflow_dispatch:
inputs:
note:
description: 'Note'
required: false
default: ''
pull_request:
push:
tags:
- '*'
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.19
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry docker.io
if: github.event_name != 'pull_request'
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
distribution: goreleaser
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: lbcd-${{ github.sha }}
path: |
dist/checksums.txt
dist/*.tar.gz

17
.gitignore vendored
View file

@ -3,6 +3,7 @@
# Databases
btcd.db
lbcd.db
*-shm
*-wal
@ -33,6 +34,22 @@ _testmain.go
*.exe
.DS_Store
# Code coverage files
profile.tmp
profile.cov
# IDE
.idea
.vscode
# Binaries
btcd
btcctl
lbcd
lbcctl
# CI artifacts
dist
debug

152
.golangci.yml Normal file
View file

@ -0,0 +1,152 @@
linters-settings:
depguard:
list-type: blacklist
packages:
# logging is allowed only by logutils.Log, logrus
# is allowed to use only in logutils package
- github.com/sirupsen/logrus
packages-with-error-message:
- github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
dupl:
threshold: 100
funlen:
lines: 100
statements: 50
gci:
local-prefixes: github.com/golangci/golangci-lint
goconst:
min-len: 2
min-occurrences: 2
gocritic:
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
disabled-checks:
- dupImport # https://github.com/go-critic/go-critic/issues/845
- ifElseChain
- octalLiteral
- whyNoLint
- wrapperFunc
gocyclo:
min-complexity: 15
goimports:
local-prefixes: github.com/golangci/golangci-lint
gomnd:
settings:
mnd:
# don't include the "operation" and "assign"
checks:
- argument
- case
- condition
- return
govet:
check-shadowing: true
settings:
printf:
funcs:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
lll:
line-length: 140
maligned:
suggest-new: true
misspell:
locale: US
nolintlint:
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
allow-unused: false # report any unused nolint directives
require-explanation: false # don't require an explanation for nolint directives
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
linters:
disable-all: true
enable:
- asciicheck
- bodyclose
# - deadcode
- depguard
# - dogsled
# - dupl
# - errcheck
# - exhaustive
- exportloopref
# - funlen
# - gochecknoglobals
# - gochecknoinits
# - gocognit
# - goconst
# - gocritic
# - gocyclo
# - godot
# - godox
# - goerr113
- gofmt
- goimports
# - gomnd
- goprintffuncname
# - gosec
# - gosimple
# - govet
# - ineffassign
# - interfacer
# - lll
# - maligned
# - misspell
- nakedret
# - nestif
# - noctx
# - nolintlint
# - prealloc
- rowserrcheck
# - revive
# - scopelint
# - staticcheck
# - structcheck
# - stylecheck
# - testpackage
# - typecheck
- unconvert
# - unparam
# - unused
# - varcheck
# - whitespace
# - wsl
issues:
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
- path: _test\.go
linters:
- gomnd
- path: pkg/golinters/errcheck.go
text: "SA1019: errCfg.Exclude is deprecated: use ExcludeFunctions instead"
- path: pkg/commands/run.go
text: "SA1019: lsc.Errcheck.Exclude is deprecated: use ExcludeFunctions instead"
# TODO must be removed after the release of the next version (v1.41.0)
- path: pkg/commands/run.go
linters:
- gomnd
# TODO must be removed after the release of the next version (v1.41.0)
- path: pkg/golinters/nolintlint/nolintlint.go
linters:
- gomnd
# TODO must be removed after the release of the next version (v1.41.0)
- path: pkg/printers/tab.go
linters:
- gomnd
run:
skip-dirs:
- test/testdata_etc
- internal/cache
- internal/renameio
- internal/robustio

68
.goreleaser.yml Normal file
View file

@ -0,0 +1,68 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
- go generate ./...
builds:
-
main: .
id: "lbcd"
binary: "lbcd"
env:
- CGO_ENABLED=0
flags:
- -trimpath
ldflags:
- -s -w
- -buildid=
- -X github.com/lbryio/lbcd/version.appTag={{ .Tag }}
targets:
- linux_amd64
- linux_arm64
- darwin_amd64
- darwin_arm64
- windows_amd64
mod_timestamp: '{{ .CommitTimestamp }}'
-
main: ./cmd/lbcctl
id: "lbcctl"
binary: "lbcctl"
flags:
- -trimpath
ldflags:
- -s -w
- -buildid=
- -X github.com/lbryio/lbcd/version.appTag={{ .Tag }}
env:
- CGO_ENABLED=0
targets:
- linux_amd64
- linux_arm64
- darwin_amd64
- darwin_arm64
- windows_amd64
mod_timestamp: '{{ .CommitTimestamp }}'
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Version }}+{{ .Commit }}"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
dockers:
- use: buildx
dockerfile: Dockerfile.goreleaser
image_templates:
- "docker.io/lbry/lbcd:{{ .Tag }}"
- "docker.io/lbry/lbcd:latest"
release:
draft: true
prerelease: auto

1230
CHANGES

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,24 @@
# This Dockerfile builds btcd from source and creates a small (55 MB) docker container based on alpine linux.
# This Dockerfile builds lbcd from source and creates a small (55 MB) docker container based on alpine linux.
#
# Clone this repository and run the following command to build and tag a fresh btcd amd64 container:
# Clone this repository and run the following command to build and tag a fresh lbcd amd64 container:
#
# docker build . -t yourregistry/btcd
# docker build . -t yourregistry/lbcd
#
# You can use the following command to buid an arm64v8 container:
#
# docker build . -t yourregistry/btcd --build-arg ARCH=arm64v8
# docker build . -t yourregistry/lbcd --build-arg ARCH=arm64v8
#
# For more information how to use this docker image visit:
# https://github.com/btcsuite/btcd/tree/master/docs
# https://github.com/lbryio/lbcd/tree/master/docs
#
# 8333 Mainnet Bitcoin peer-to-peer port
# 8334 Mainet RPC port
# 9246 Mainnet LBRY peer-to-peer port
# 9245 Mainet RPC port
ARG ARCH=amd64
FROM golang:1.14-alpine3.12 AS build-container
FROM golang:1.19 AS build-container
ARG ARCH
ENV GO111MODULE=on
ADD . /app
WORKDIR /app
@ -30,12 +29,12 @@ RUN set -ex \
&& echo "Compiling for $GOARCH" \
&& go install -v . ./cmd/...
FROM $ARCH/alpine:3.12
FROM $ARCH/debian:bullseye-20220418-slim
COPY --from=build-container /go/bin /bin
VOLUME ["/root/.btcd"]
VOLUME ["/root/.lbcd"]
EXPOSE 8333 8334
EXPOSE 9245 9246
ENTRYPOINT ["btcd"]
ENTRYPOINT ["lbcd"]

9
Dockerfile.goreleaser Normal file
View file

@ -0,0 +1,9 @@
FROM debian:bullseye-20220418-slim
COPY lbcd lbcctl /bin/
VOLUME ["/root/.lbcd"]
EXPOSE 9245 9246
ENTRYPOINT ["lbcd"]

View file

@ -1,5 +1,6 @@
ISC License
Copyright (c) 2021 The LBRY developers
Copyright (c) 2013-2017 The btcsuite developers
Copyright (c) 2015-2016 The Decred developers

364
README.md
View file

@ -1,121 +1,335 @@
btcd
====
# lbcd
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![Coverage Status](https://coveralls.io/repos/github/btcsuite/btcd/badge.svg?branch=master)](https://coveralls.io/github/btcsuite/btcd?branch=master)
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions)
[![Coverage Status](https://coveralls.io/repos/github/lbryio/lbcd/badge.svg?branch=master)](https://coveralls.io/github/lbryio/lbcd?branch=master)
[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd)
<!--[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd)-->
btcd is an alternative full node bitcoin implementation written in Go (golang).
**lbcd** is a full node implementation of LBRY's blockchain written in Go (golang).
This project is currently under active development and is in a Beta state. It
is extremely stable and has been in production use since October 2013.
Software stack developed by LBRY teams has been all migrated to **lbcd**.
It properly downloads, validates, and serves the block chain using the exact
rules (including consensus bugs) for block acceptance as Bitcoin Core. We have
taken great care to avoid btcd causing a fork to the block chain. It includes a
full block validation testing framework which contains all of the 'official'
block acceptance tests (and some additional ones) that is run on every pull
request to help ensure it properly follows consensus. Also, it passes all of
the JSON test data in the Bitcoin Core code.
We're working with exchanges and pool oerators to migrate from **lbrycrd** to **lbcd**.
It also properly relays newly mined blocks, maintains a transaction pool, and
relays individual transactions that have not yet made it into a block. It
ensures all individual transactions admitted to the pool follow the rules
required by the block chain and also includes more strict checks which filter
transactions based on miner requirements ("standard" transactions).
If you're integrating with **lbcd+lbcwallet**, please check the Wiki for current [supported RPCs](wiki/RPC-availability).
One key difference between btcd and Bitcoin Core is that btcd does *NOT* include
wallet functionality and this was a very intentional design decision. See the
blog entry [here](https://web.archive.org/web/20171125143919/https://blog.conformal.com/btcd-not-your-moms-bitcoin-daemon)
for more details. This means you can't actually make or receive payments
directly with btcd. That functionality is provided by the
[btcwallet](https://github.com/btcsuite/btcwallet) and
[Paymetheus](https://github.com/btcsuite/Paymetheus) (Windows-only) projects
which are both under active development.
Note: **lbcd** does *NOT* include wallet functionality. That functionality is provided by the
[lbcwallet](https://github.com/lbryio/lbcwallet) and the [LBRY SDK](https://github.com/lbryio/lbry-sdk).
## Requirements
[Go](http://golang.org) 1.14 or newer.
All common operating systems are supported. lbcd requires at least 8GB of RAM
and at least 100GB of disk storage. Both RAM and disk requirements increase slowly over time.
Using a fast NVMe disk is recommended.
## Installation
https://github.com/btcsuite/btcd/releases
Acquire binary files from [releases](https://github.com/lbryio/lbcd/releases)
#### Linux/BSD/MacOSX/POSIX - Build from Source
For compilation, [Go](http://golang.org) 1.19 or newer is required.
Install Go according to its [installation instructions](http://golang.org/doc/install).
- Install Go according to the installation instructions here:
http://golang.org/doc/install
``` sh
# lbcd (full node)
$ go install github.com/lbryio/lbcd@latest
- Ensure Go was installed properly and is a supported version:
```bash
$ go version
$ go env GOROOT GOPATH
# lbcctl (rpc client utility)
$ go install github.com/lbryio/lbcd/cmd/lbcctl@latest
```
NOTE: The `GOROOT` and `GOPATH` above must not be the same path. It is
recommended that `GOPATH` is set to a directory in your home directory such as
`~/goprojects` to avoid write permission issues. It is also recommended to add
`$GOPATH/bin` to your `PATH` at this point.
## Usage
- Run the following commands to obtain btcd, all dependencies, and install it:
Default application folder `${LBCDDIR}`:
```bash
$ cd $GOPATH/src/github.com/btcsuite/btcd
$ GO111MODULE=on go install -v . ./cmd/...
- Linux: `~/.lbcd/`
- MacOS: `/Users/<username>/Library/Application Support/Lbcd/`
### Start the **lbcd**
``` sh
./lbcd
```
- btcd (and utilities) will now be installed in ```$GOPATH/bin```. If you did
not already add the bin directory to your system path during Go installation,
we recommend you do so now.
**lbcd** loads config file at `"${LBCDDIR}/lbcd.conf"`.
## Updating
If no config is found, it creates a [default one](sample-lbcd.conf), which includes all available options with default settings except randomly generated *RPC credentials* (see below).
#### Linux/BSD/MacOSX/POSIX - Build from Source
### RPC server
- Run the following commands to update btcd, all dependencies, and install it:
RPC credentials (`rpcuser` and `rpcpass`) is required to enable RPC server. It can be specify in the `"${LBCDDIR}/lbcd.conf"`, using command line options:
```bash
$ cd $GOPATH/src/github.com/btcsuite/btcd
$ git pull
$ GO111MODULE=on go install -v . ./cmd/...
``` sh
./lbcd --rpcuser=rpcuser --rpcpass=rpcpass
2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on 0.0.0.0:9245
2022-07-28 12:28:19.627 [INF] RPCS: RPC server listening on [::]:9245
```
## Getting Started
### Working with TLS (Default)
btcd has several configuration options available to tweak how it runs, but all
of the basic operations described in the intro section work with zero
configuration.
By default, **lbcd** runs RPC server with TLS enabled, and generates the `rpc.cert` and `rpc.key` under `${LBCDDIR}`, if not exist already.
#### Linux/BSD/POSIX/Source
To interact with the RPC server, a client has to either specify the `rpc.cert`, or disable the certification verification for TLS.
```bash
$ ./btcd
Interact with **lbcd** RPC using `lbcctl`
``` sh
$ ./lbcctl --rpccert "${LBCDDIR}/rpc.cert" getblockcount
# or disable the certificate verification
$ ./lbcctl --skipverify getblockcount
1200062
```
## IRC
Interact with **lbcd** RPC using `curl`
- irc.freenode.net
- channel #btcd
- [webchat](https://webchat.freenode.net/?channels=btcd)
``` sh
$ curl --user rpcuser:rpcpass \
--cacert "${LBCDDIR}/rpc.cert" \
--data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
-H 'content-type: text/plain;' \
https://127.0.0.1:9245/
## Issue Tracker
# or disable the certificate verification
$ curl --user rpcuser:rpcpass \
--insecure \
--data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
-H 'content-type: text/plain;' \
https://127.0.0.1:9245/
```
The [integrated github issue tracker](https://github.com/btcsuite/btcd/issues)
is used for this project.
``` json
{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"}
```
## Documentation
### Working without TLS
The documentation is a work-in-progress. It is located in the [docs](https://github.com/btcsuite/btcd/tree/master/docs) folder.
TLS can be disabled using the `--notls` option:
## Release Verification
``` sh
$ ./lbcd --notls
```
``` sh
$ ./lbcctl --notls getblockcount
1200062
```
``` sh
$ curl --user rpcuser:rpcpass \
--data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' \
-H 'content-type: text/plain;' \
http://127.0.0.1:9245/
```
``` json
{"jsonrpc":"1.0","result":1200062,"error":null,"id":"curltest"}
```
## Using Snapshots (optional)
[Snapshots](https://snapshots.lbry.com/blockchain/) are created bi-weekly to help new users catch up current block height.
The snapshots are archived and compressed in [zstd](https://facebook.github.io/zstd/) format for it's compression ratio and speed.
Download the snapshot, and uncompress it:
``` sh
time curl -O https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst
zstd -d --stdout lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | tar xf - -C "${LBCDDIR}"
```
If preferred, a user can download and uncompress the snapshot on the fly:
By the time the download is finished, the snapshots should be almost uncompressed already.
``` sh
mkdir -p "${LBCDDIR}"
time curl https://snapshots.lbry.com/blockchain/lbcd_snapshot_1199527_v0.22.105_2022-07-27.tar.zst | zstd -d --stdout | tar xf - -C "${LBCDDIR}"
# % Total % Received % Xferd Average Speed Time Time Time Current
# Dload Upload Total Spent Left Speed
# 100 64.9G 100 64.9G 0 0 37.0M 0 0:29:49 0:29:49 --:--:-- 33.0M
#
# real 29m49.962s
# user 6m53.710s
# sys 8m56.545s
```
## Working with RPCs
Using `lbcctl -l` to list available RPCs:
``` sh
$ lbcctl -l
Chain Server Commands:
addnode "addr" "add|remove|onetry"
createrawtransaction [{"txid":"value","vout":n},...] {"address":amount,...} (locktime)
debuglevel "levelspec"
decoderawtransaction "hextx"
decodescript "hexscript"
deriveaddresses "descriptor" ({"value":value})
fundrawtransaction "hextx" {"changeaddress":changeaddress,"changeposition":changeposition,"changetype":changetype,"includewatching":includewatching,"lockunspents":lockunspents,"feerate":feerate,"subtractfeefromoutputs":[subtractfeefromoutput,...],"replaceable":replaceable,"conftarget":conftarget,"estimatemode":estimatemode} (iswitness)
generate numblocks
[skipped]
Wallet Server Commands (--wallet):
addmultisigaddress nrequired ["key",...] ("account")
addwitnessaddress "address"
backupwallet "destination"
createmultisig nrequired ["key",...]
createnewaccount "account"
createwallet "walletname" (disableprivatekeys=false blank=false passphrase="" avoidreuse=false)
dumpprivkey "address"
dumpwallet "filename"
encryptwallet "passphrase"
estimatefee numblocks
estimatepriority numblocks
estimatesmartfee conftarget (estimatemode="CONSERVATIVE")
getaccount "address"
getaccountaddress "account"
getaddressesbyaccount "account"
[skipped]
```
Using `lbcctl help rpcname` to show the RPC spec:
``` sh
$ lbcctl help getblock
getblock "hash" (verbosity=1)
Returns information about a block given its hash.
Arguments:
1. hash (string, required) The hash of the block
2. verbosity (numeric, optional, default=1) Specifies whether the block data should be returned as a hex-encoded string (0), as parsed data with a slice of TXIDs (1), or as parsed data with parsed transaction data (2)
Result (verbosity=0):
"value" (string) Hex-encoded bytes of the serialized block
Result (verbosity=1):
{
"getblockverboseresultbase": { (object)
"hash": "value", (string) The hash of the block (same as provided)
"confirmations": n, (numeric) The number of confirmations
"strippedsize": n, (numeric) The size of the block without witness data
"size": n, (numeric) The size of the block
"weight": n, (numeric) The weight of the block
"height": n, (numeric) The height of the block in the block chain
"version": n, (numeric) The block version
"versionHex": "value", (string) The block version in hexadecimal
"merkleroot": "value", (string) Root hash of the merkle tree
"time": n, (numeric) The block time in seconds since 1 Jan 1970 GMT
"mediantime": n, (numeric) The median block time in seconds since 1 Jan 1970 GMT
"nonce": n, (numeric) The block nonce
"bits": "value", (string) The bits which represent the block difficulty
"difficulty": n.nnn, (numeric) The proof-of-work difficulty as a multiple of the minimum difficulty
"chainwork": "value", (string) Expected number of hashes required to produce the chain up to this block (in hex)
"previousblockhash": "value", (string) The hash of the previous block
"nextblockhash": "value", (string) The hash of the next block (only if there is one)
"nameclaimroot": "value", (string) Root hash of the claim trie
"nTx": n, (numeric) The number of transactions (aka, count of TX)
},
"tx": ["value",...], (array of string) The transaction hashes (only when verbosity=1)
}
```
## **lbcd** & **lbcwallet**
*Wallet* related functianlities and RPCs are provided by a separate programe - [**lbcwallet**](https://github.com/lbryio/lbcwallet).
Once setup, lbcwallet can serve wallet related RPCs as well as proxy lbcd RPCs to an assocated lbcd now.
It's sufficient for user to connect just the **lbcwallet** instead of both.
``` mermaid
sequenceDiagram
actor C as lbcctl
participant W as lbcwallet (port: 9244)
participant D as lbcd (port: 9245)
rect rgb(200,200,200)
Note over C,D: lbcctl getblockcount
C ->>+ D: getblockcount
D -->>- C: response
end
rect rgb(200,200,200)
Note over C,W: lbcctl --wallet balance
C ->>+ W: getbalance
W -->>- C: response
end
rect rgb(200,200,200)
Note over C,D: lbcctl --wallet getblockcount (lbcd RPC service proxied by lbcwallet)
C ->>+ W: getblockcount
W ->>+ D: getblockcount
D -->>- W: response
W -->>- C: response
end
```
While **lbcd** can run standalone as a full node, **lbcwallet** requires an associated **lbcd** instance for scanning and sync'ing block data.
``` mermaid
sequenceDiagram
participant W as lbcwallet (RPC port: 9244)
participant D as lbcd (RPC port: 9245, P2P port: 9246)
participant D2 as other lbcd node(s) (P2P port: 9246)
rect rgb(200,200,200)
Note over W,D: Asynchronous websocket notifications
W ->> D: subscribe to notifications
D -->> W: notification
D -->> W: notification
end
rect rgb(200,200,200)
Note over W,D: lbcd RPCs
W ->>+ D: getblockheader
D ->>- W: response
end
rect rgb(200,200,200)
Note over D,D2: P2P messages over port 9246
D -->> D2: P2P message
D2 -->> D: P2P message
end
```
## Data integrity
**lbcd** is not immune to data loss. It expects a clean shutdown via SIGINT or
SIGTERM. SIGKILL, immediate VM kills, and sudden power loss can cause data
corruption, thus requiring chain resynchronization for recovery.
## Security
We take security seriously. Please contact [security](mailto:security@lbry.com) regarding any security issues.
Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it.
We maintain a mailing list for notifications of upgrades, security issues,
and soft/hard forks. To join, visit [fork list](https://lbry.com/forklist)
## Contributing
Contributions to this project are welcome, encouraged, and compensated.
The [integrated github issue tracker](https://github.com/lbryio/lbcd/issues)
is used for this project. All pull requests will be considered.
<!-- ## Release Verification
Please see our [documentation on the current build/verification
process](https://github.com/btcsuite/btcd/tree/master/release) for all our
process](https://github.com/lbryio/lbcd/tree/master/release) for all our
releases for information on how to verify the integrity of published releases
using our reproducible build system.
-->
## License
btcd is licensed under the [copyfree](http://copyfree.org) ISC License.
lbcd is licensed under the [copyfree](http://copyfree.org) ISC License.

View file

@ -23,8 +23,8 @@ import (
"sync/atomic"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
)
// AddrManager provides a concurrency safe address manager for caching potential
@ -45,7 +45,7 @@ type AddrManager struct {
nTried int
nNew int
lamtx sync.Mutex
localAddresses map[string]*localAddress
localAddresses map[string]*LocalAddress
version int
}
@ -69,9 +69,9 @@ type serializedAddrManager struct {
TriedBuckets [triedBucketCount][]string
}
type localAddress struct {
na *wire.NetAddress
score AddressPriority
type LocalAddress struct {
NA *wire.NetAddress
Score AddressPriority
}
// AddressPriority type is used to describe the hierarchy of local address
@ -176,9 +176,9 @@ func (a *AddrManager) updateAddress(netAddr, srcAddr *wire.NetAddress) {
// TODO: only update addresses periodically.
// Update the last seen time and services.
// note that to prevent causing excess garbage on getaddr
// messages the netaddresses in addrmaanger are *immutable*,
// messages the netaddresses in addrmanager are *immutable*,
// if we need to change them then we replace the pointer with a
// new copy so that we don't have to copy every na for getaddr.
// new copy so that we don't have to copy every NA for getaddr.
if netAddr.Timestamp.After(ka.na.Timestamp) ||
(ka.na.Services&netAddr.Services) !=
netAddr.Services {
@ -186,7 +186,9 @@ func (a *AddrManager) updateAddress(netAddr, srcAddr *wire.NetAddress) {
naCopy := *ka.na
naCopy.Timestamp = netAddr.Timestamp
naCopy.AddService(netAddr.Services)
ka.mtx.Lock()
ka.na = &naCopy
ka.mtx.Unlock()
}
// If already in tried, we have nothing to do here.
@ -753,7 +755,7 @@ func (a *AddrManager) HostToNetAddress(host string, port uint16, services wire.S
// the relevant .onion address.
func ipString(na *wire.NetAddress) string {
if IsOnionCatTor(na) {
// We know now that na.IP is long enough.
// We know now that NA.IP is long enough.
base32 := base32.StdEncoding.EncodeToString(na.IP[6:])
return strings.ToLower(base32) + ".onion"
}
@ -857,8 +859,11 @@ func (a *AddrManager) Attempt(addr *wire.NetAddress) {
return
}
// set last tried time to now
now := time.Now()
ka.mtx.Lock()
ka.attempts++
ka.lastattempt = time.Now()
ka.lastattempt = now
ka.mtx.Unlock()
}
// Connected Marks the given address as currently connected and working at the
@ -877,10 +882,12 @@ func (a *AddrManager) Connected(addr *wire.NetAddress) {
// so.
now := time.Now()
if now.After(ka.na.Timestamp.Add(time.Minute * 20)) {
// ka.na is immutable, so replace it.
// ka.NA is immutable, so replace it.
naCopy := *ka.na
naCopy.Timestamp = time.Now()
ka.mtx.Lock()
ka.na = &naCopy
ka.mtx.Unlock()
}
}
@ -899,11 +906,13 @@ func (a *AddrManager) Good(addr *wire.NetAddress) {
// ka.Timestamp is not updated here to avoid leaking information
// about currently connected peers.
now := time.Now()
ka.mtx.Lock()
ka.lastsuccess = now
ka.lastattempt = now
ka.attempts = 0
ka.mtx.Unlock() // tried and refs synchronized via a.mtx
// move to tried set, optionally evicting other addresses if neeed.
// move to tried set, optionally evicting other addresses if need.
if ka.tried {
return
}
@ -985,14 +994,16 @@ func (a *AddrManager) SetServices(addr *wire.NetAddress, services wire.ServiceFl
// Update the services if needed.
if ka.na.Services != services {
// ka.na is immutable, so replace it.
// ka.NA is immutable, so replace it.
naCopy := *ka.na
naCopy.Services = services
ka.mtx.Lock()
ka.na = &naCopy
ka.mtx.Unlock()
}
}
// AddLocalAddress adds na to the list of known local addresses to advertise
// AddLocalAddress adds NA to the list of known local addresses to advertise
// with the given priority.
func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPriority) error {
if !IsRoutable(na) {
@ -1004,13 +1015,13 @@ func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPrior
key := NetAddressKey(na)
la, ok := a.localAddresses[key]
if !ok || la.score < priority {
if !ok || la.Score < priority {
if ok {
la.score = priority + 1
la.Score = priority + 1
} else {
a.localAddresses[key] = &localAddress{
na: na,
score: priority,
a.localAddresses[key] = &LocalAddress{
NA: na,
Score: priority,
}
}
}
@ -1106,12 +1117,12 @@ func (a *AddrManager) GetBestLocalAddress(remoteAddr *wire.NetAddress) *wire.Net
var bestscore AddressPriority
var bestAddress *wire.NetAddress
for _, la := range a.localAddresses {
reach := getReachabilityFrom(la.na, remoteAddr)
reach := getReachabilityFrom(la.NA, remoteAddr)
if reach > bestreach ||
(reach == bestreach && la.score > bestscore) {
(reach == bestreach && la.Score > bestscore) {
bestreach = reach
bestscore = la.score
bestAddress = la.na
bestscore = la.Score
bestAddress = la.NA
}
}
if bestAddress != nil {
@ -1135,6 +1146,15 @@ func (a *AddrManager) GetBestLocalAddress(remoteAddr *wire.NetAddress) *wire.Net
return bestAddress
}
// LocalAddresses returns the list of local addresses for our node.
func (a *AddrManager) LocalAddresses() []*LocalAddress {
var addrs []*LocalAddress
for _, addr := range a.localAddresses {
addrs = append(addrs, addr)
}
return addrs
}
// New returns a new bitcoin address manager.
// Use Start to begin processing asynchronous address updates.
func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager {
@ -1143,7 +1163,7 @@ func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager
lookupFunc: lookupFunc,
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
quit: make(chan struct{}),
localAddresses: make(map[string]*localAddress),
localAddresses: make(map[string]*LocalAddress),
version: serialisationVersion,
}
am.reset()

View file

@ -7,7 +7,7 @@ import (
"os"
"testing"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
// randAddr generates a *wire.NetAddress backed by a random IPv4/IPv6 address.

View file

@ -12,8 +12,8 @@ import (
"testing"
"time"
"github.com/btcsuite/btcd/addrmgr"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/addrmgr"
"github.com/lbryio/lbcd/wire"
)
// naTest is used to describe a test to be performed against the NetAddressKey
@ -34,61 +34,61 @@ var someIP = "173.194.115.66"
func addNaTests() {
// IPv4
// Localhost
addNaTest("127.0.0.1", 8333, "127.0.0.1:8333")
addNaTest("127.0.0.1", 8334, "127.0.0.1:8334")
addNaTest("127.0.0.1", 9244, "127.0.0.1:9244")
addNaTest("127.0.0.1", 9245, "127.0.0.1:9245")
// Class A
addNaTest("1.0.0.1", 8333, "1.0.0.1:8333")
addNaTest("2.2.2.2", 8334, "2.2.2.2:8334")
addNaTest("27.253.252.251", 8335, "27.253.252.251:8335")
addNaTest("123.3.2.1", 8336, "123.3.2.1:8336")
addNaTest("1.0.0.1", 9244, "1.0.0.1:9244")
addNaTest("2.2.2.2", 9245, "2.2.2.2:9245")
addNaTest("27.253.252.251", 9246, "27.253.252.251:9246")
addNaTest("123.3.2.1", 9247, "123.3.2.1:9247")
// Private Class A
addNaTest("10.0.0.1", 8333, "10.0.0.1:8333")
addNaTest("10.1.1.1", 8334, "10.1.1.1:8334")
addNaTest("10.2.2.2", 8335, "10.2.2.2:8335")
addNaTest("10.10.10.10", 8336, "10.10.10.10:8336")
addNaTest("10.0.0.1", 9244, "10.0.0.1:9244")
addNaTest("10.1.1.1", 9245, "10.1.1.1:9245")
addNaTest("10.2.2.2", 9246, "10.2.2.2:9246")
addNaTest("10.10.10.10", 9247, "10.10.10.10:9247")
// Class B
addNaTest("128.0.0.1", 8333, "128.0.0.1:8333")
addNaTest("129.1.1.1", 8334, "129.1.1.1:8334")
addNaTest("180.2.2.2", 8335, "180.2.2.2:8335")
addNaTest("191.10.10.10", 8336, "191.10.10.10:8336")
addNaTest("128.0.0.1", 9244, "128.0.0.1:9244")
addNaTest("129.1.1.1", 9245, "129.1.1.1:9245")
addNaTest("180.2.2.2", 9246, "180.2.2.2:9246")
addNaTest("191.10.10.10", 9247, "191.10.10.10:9247")
// Private Class B
addNaTest("172.16.0.1", 8333, "172.16.0.1:8333")
addNaTest("172.16.1.1", 8334, "172.16.1.1:8334")
addNaTest("172.16.2.2", 8335, "172.16.2.2:8335")
addNaTest("172.16.172.172", 8336, "172.16.172.172:8336")
addNaTest("172.16.0.1", 9244, "172.16.0.1:9244")
addNaTest("172.16.1.1", 9245, "172.16.1.1:9245")
addNaTest("172.16.2.2", 9246, "172.16.2.2:9246")
addNaTest("172.16.172.172", 9247, "172.16.172.172:9247")
// Class C
addNaTest("193.0.0.1", 8333, "193.0.0.1:8333")
addNaTest("200.1.1.1", 8334, "200.1.1.1:8334")
addNaTest("205.2.2.2", 8335, "205.2.2.2:8335")
addNaTest("223.10.10.10", 8336, "223.10.10.10:8336")
addNaTest("193.0.0.1", 9244, "193.0.0.1:9244")
addNaTest("200.1.1.1", 9245, "200.1.1.1:9245")
addNaTest("205.2.2.2", 9246, "205.2.2.2:9246")
addNaTest("223.10.10.10", 9247, "223.10.10.10:9247")
// Private Class C
addNaTest("192.168.0.1", 8333, "192.168.0.1:8333")
addNaTest("192.168.1.1", 8334, "192.168.1.1:8334")
addNaTest("192.168.2.2", 8335, "192.168.2.2:8335")
addNaTest("192.168.192.192", 8336, "192.168.192.192:8336")
addNaTest("192.168.0.1", 9244, "192.168.0.1:9244")
addNaTest("192.168.1.1", 9245, "192.168.1.1:9245")
addNaTest("192.168.2.2", 9246, "192.168.2.2:9246")
addNaTest("192.168.192.192", 9247, "192.168.192.192:9247")
// IPv6
// Localhost
addNaTest("::1", 8333, "[::1]:8333")
addNaTest("fe80::1", 8334, "[fe80::1]:8334")
addNaTest("::1", 9244, "[::1]:9244")
addNaTest("fe80::1", 9245, "[fe80::1]:9245")
// Link-local
addNaTest("fe80::1:1", 8333, "[fe80::1:1]:8333")
addNaTest("fe91::2:2", 8334, "[fe91::2:2]:8334")
addNaTest("fea2::3:3", 8335, "[fea2::3:3]:8335")
addNaTest("feb3::4:4", 8336, "[feb3::4:4]:8336")
addNaTest("fe80::1:1", 9244, "[fe80::1:1]:9244")
addNaTest("fe91::2:2", 9245, "[fe91::2:2]:9245")
addNaTest("fea2::3:3", 9246, "[fea2::3:3]:9246")
addNaTest("feb3::4:4", 9247, "[feb3::4:4]:9247")
// Site-local
addNaTest("fec0::1:1", 8333, "[fec0::1:1]:8333")
addNaTest("fed1::2:2", 8334, "[fed1::2:2]:8334")
addNaTest("fee2::3:3", 8335, "[fee2::3:3]:8335")
addNaTest("fef3::4:4", 8336, "[fef3::4:4]:8336")
addNaTest("fec0::1:1", 9244, "[fec0::1:1]:9244")
addNaTest("fed1::2:2", 9245, "[fed1::2:2]:9245")
addNaTest("fee2::3:3", 9246, "[fee2::3:3]:9246")
addNaTest("fef3::4:4", 9247, "[fef3::4:4]:9247")
}
func addNaTest(ip string, port uint16, want string) {
@ -119,7 +119,7 @@ func TestAddAddressByIP(t *testing.T) {
err error
}{
{
someIP + ":8333",
someIP + ":9244",
nil,
},
{
@ -127,7 +127,7 @@ func TestAddAddressByIP(t *testing.T) {
addrErr,
},
{
someIP[:12] + ":8333",
someIP[:12] + ":9244",
fmtErr,
},
{
@ -212,7 +212,7 @@ func TestAttempt(t *testing.T) {
n := addrmgr.New("testattempt", lookupFunc)
// Add a new address and get it
err := n.AddAddressByIP(someIP + ":8333")
err := n.AddAddressByIP(someIP + ":9244")
if err != nil {
t.Fatalf("Adding address failed: %v", err)
}
@ -234,7 +234,7 @@ func TestConnected(t *testing.T) {
n := addrmgr.New("testconnected", lookupFunc)
// Add a new address and get it
err := n.AddAddressByIP(someIP + ":8333")
err := n.AddAddressByIP(someIP + ":9244")
if err != nil {
t.Fatalf("Adding address failed: %v", err)
}
@ -261,14 +261,14 @@ func TestNeedMoreAddresses(t *testing.T) {
var err error
for i := 0; i < addrsToAdd; i++ {
s := fmt.Sprintf("%d.%d.173.147:8333", i/128+60, i%128+60)
s := fmt.Sprintf("%d.%d.173.147:9244", i/128+60, i%128+60)
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
if err != nil {
t.Errorf("Failed to turn %s into an address: %v", s, err)
}
}
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 9244, 0)
n.AddAddresses(addrs, srcAddr)
numAddrs := n.NumAddresses()
@ -289,14 +289,14 @@ func TestGood(t *testing.T) {
var err error
for i := 0; i < addrsToAdd; i++ {
s := fmt.Sprintf("%d.173.147.%d:8333", i/64+60, i%64+60)
s := fmt.Sprintf("%d.173.147.%d:9244", i/64+60, i%64+60)
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
if err != nil {
t.Errorf("Failed to turn %s into an address: %v", s, err)
}
}
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 9244, 0)
n.AddAddresses(addrs, srcAddr)
for _, addr := range addrs {
@ -323,7 +323,7 @@ func TestGetAddress(t *testing.T) {
}
// Add a new address and get it
err := n.AddAddressByIP(someIP + ":8333")
err := n.AddAddressByIP(someIP + ":9244")
if err != nil {
t.Fatalf("Adding address failed: %v", err)
}

View file

@ -5,7 +5,7 @@
/*
Package addrmgr implements concurrency safe Bitcoin address manager.
Address Manager Overview
# Address Manager Overview
In order maintain the peer-to-peer Bitcoin network, there needs to be a source
of addresses to connect to as nodes come and go. The Bitcoin protocol provides

View file

@ -7,7 +7,7 @@ package addrmgr
import (
"time"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
func TstKnownAddressIsBad(ka *KnownAddress) bool {

View file

@ -5,14 +5,16 @@
package addrmgr
import (
"sync"
"time"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
// KnownAddress tracks information about a known network address that is used
// to determine how viable an address is.
type KnownAddress struct {
mtx sync.RWMutex // na and lastattempt
na *wire.NetAddress
srcAddr *wire.NetAddress
attempts int
@ -25,19 +27,28 @@ type KnownAddress struct {
// NetAddress returns the underlying wire.NetAddress associated with the
// known address.
func (ka *KnownAddress) NetAddress() *wire.NetAddress {
ka.mtx.RLock()
defer ka.mtx.RUnlock()
return ka.na
}
// LastAttempt returns the last time the known address was attempted.
func (ka *KnownAddress) LastAttempt() time.Time {
ka.mtx.RLock()
defer ka.mtx.RUnlock()
return ka.lastattempt
}
// Services returns the services supported by the peer with the known address.
func (ka *KnownAddress) Services() wire.ServiceFlag {
ka.mtx.RLock()
defer ka.mtx.RUnlock()
return ka.na.Services
}
// The unexported methods, chance and isBad, are used from within AddrManager
// where KnownAddress field access is synchronized via it's own Mutex.
// chance returns the selection probability for a known address. The priority
// depends upon how recently the address has been seen, how recently it was last
// attempted and how often attempts to connect to it have failed.

View file

@ -9,8 +9,8 @@ import (
"testing"
"time"
"github.com/btcsuite/btcd/addrmgr"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/addrmgr"
"github.com/lbryio/lbcd/wire"
)
func TestChance(t *testing.T) {

View file

@ -8,7 +8,7 @@ import (
"fmt"
"net"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
var (

View file

@ -8,8 +8,8 @@ import (
"net"
"testing"
"github.com/btcsuite/btcd/addrmgr"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/addrmgr"
"github.com/lbryio/lbcd/wire"
)
// TestIPTypes ensures the various functions which determine the type of an IP
@ -39,7 +39,7 @@ func TestIPTypes(t *testing.T) {
rfc4193, rfc4380, rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598,
local, valid, routable bool) ipTest {
nip := net.ParseIP(ip)
na := *wire.NewNetAddressIPPort(nip, 8333, wire.SFNodeNetwork)
na := *wire.NewNetAddressIPPort(nip, 9246, wire.SFNodeNetwork)
test := ipTest{na, rfc1918, rfc2544, rfc3849, rfc3927, rfc3964, rfc4193, rfc4380,
rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598, local, valid, routable}
return test
@ -192,7 +192,7 @@ func TestGroupKey(t *testing.T) {
for i, test := range tests {
nip := net.ParseIP(test.ip)
na := *wire.NewNetAddressIPPort(nip, 8333, wire.SFNodeNetwork)
na := *wire.NewNetAddressIPPort(nip, 9246, wire.SFNodeNetwork)
if key := addrmgr.GroupKey(&na); key != test.expected {
t.Errorf("TestGroupKey #%d (%s): unexpected group key "+
"- got '%s', want '%s'", i, test.name,

View file

@ -1,30 +1,9 @@
blockchain
==========
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain)
Package blockchain implements bitcoin block handling and chain selection rules.
The test coverage is currently only around 60%, but will be increasing over
time. See `test_coverage.txt` for the gocov coverage report. Alternatively, if
you are running a POSIX OS, you can run the `cov_report.sh` script for a
real-time report. Package blockchain is licensed under the liberal ISC license.
There is an associated blog post about the release of this package
[here](https://blog.conformal.com/btcchain-the-bitcoin-chain-package-from-bctd/).
This package has intentionally been designed so it can be used as a standalone
package for any projects needing to handle processing of blocks into the bitcoin
block chain.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/blockchain
```
## Bitcoin Chain Processing Overview
### Bitcoin Chain Processing Overview
Before a block is allowed into the block chain, it must go through an intensive
series of validation rules. The following list serves as a general outline of
@ -57,47 +36,4 @@ is by no means exhaustive:
transaction values
- Run the transaction scripts to verify the spender is allowed to spend the
coins
- Insert the block into the block database
## Examples
* [ProcessBlock Example](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain#example-BlockChain-ProcessBlock)
Demonstrates how to create a new chain instance and use ProcessBlock to
attempt to add a block to the chain. This example intentionally
attempts to insert a duplicate genesis block to illustrate how an invalid
block is handled.
* [CompactToBig Example](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain#example-CompactToBig)
Demonstrates how to convert the compact "bits" in a block header which
represent the target difficulty to a big integer and display it using the
typical hex notation.
* [BigToCompact Example](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain#example-BigToCompact)
Demonstrates how to convert a target difficulty into the
compact "bits" in a block header which represent that target difficulty.
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code
has not been tampered with and is coming from the btcsuite developers. To
verify the signature perform the following:
- Download the public key from the Conformal website at
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
- Import the public key into your GPG keyring:
```bash
gpg --import GIT-GPG-KEY-conformal.txt
```
- Verify the release tag with the following command where `TAG_NAME` is a
placeholder for the specific tag:
```bash
git tag -v TAG_NAME
```
## License
Package blockchain is licensed under the [copyfree](http://copyfree.org) ISC
License.
- Insert the block into the block database

View file

@ -7,8 +7,8 @@ package blockchain
import (
"fmt"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/database"
btcutil "github.com/lbryio/lbcutil"
)
// maybeAcceptBlock potentially accepts a block into the block chain and, if
@ -84,9 +84,11 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags)
// Notify the caller that the new block was accepted into the block
// chain. The caller would typically want to react by relaying the
// inventory to other peers.
b.notificationSendLock.Lock()
defer b.notificationSendLock.Unlock()
b.chainLock.Unlock()
defer b.chainLock.Lock()
b.sendNotification(NTBlockAccepted, block)
b.chainLock.Lock()
return isMainChain, nil
}

View file

@ -6,14 +6,12 @@ package blockchain
import (
"testing"
"github.com/btcsuite/btcutil"
)
// BenchmarkIsCoinBase performs a simple benchmark against the IsCoinBase
// function.
func BenchmarkIsCoinBase(b *testing.B) {
tx, _ := btcutil.NewBlock(&Block100000).Tx(1)
tx, _ := GetBlock100000().Tx(1)
b.ResetTimer()
for i := 0; i < b.N; i++ {
IsCoinBase(tx)
@ -23,9 +21,9 @@ func BenchmarkIsCoinBase(b *testing.B) {
// BenchmarkIsCoinBaseTx performs a simple benchmark against the IsCoinBaseTx
// function.
func BenchmarkIsCoinBaseTx(b *testing.B) {
tx := Block100000.Transactions[1]
tx, _ := GetBlock100000().Tx(1)
b.ResetTimer()
for i := 0; i < b.N; i++ {
IsCoinBaseTx(tx)
IsCoinBaseTx(tx.MsgTx())
}
}

View file

@ -10,10 +10,10 @@ import (
"sync"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/wire"
)
// blockStatus is a bit field representing the validation state of the block.
@ -93,6 +93,7 @@ type blockNode struct {
nonce uint32
timestamp int64
merkleRoot chainhash.Hash
claimTrie chainhash.Hash
// status is a bitfield representing the validation state of the block. The
// status field, unlike the other fields, may be written to and so should
@ -114,6 +115,7 @@ func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *block
nonce: blockHeader.Nonce,
timestamp: blockHeader.Timestamp.Unix(),
merkleRoot: blockHeader.MerkleRoot,
claimTrie: blockHeader.ClaimTrie,
}
if parent != nil {
node.parent = parent
@ -144,6 +146,7 @@ func (node *blockNode) Header() wire.BlockHeader {
Version: node.version,
PrevBlock: *prevHash,
MerkleRoot: node.merkleRoot,
ClaimTrie: node.claimTrie,
Timestamp: time.Unix(node.timestamp, 0),
Bits: node.bits,
Nonce: node.nonce,

View file

@ -8,15 +8,18 @@ package blockchain
import (
"container/list"
"fmt"
"math/big"
"sync"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
"github.com/lbryio/lbcd/claimtrie"
)
const (
@ -34,8 +37,9 @@ const (
// from the block being located.
//
// For example, assume a block chain with a side chain as depicted below:
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
// \-> 16a -> 17a
//
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
// \-> 16a -> 17a
//
// The block locator for block 17a would be the hashes of blocks:
// [17a 16a 15 14 13 12 11 10 9 8 7 6 4 genesis]
@ -114,6 +118,12 @@ type BlockChain struct {
// fields in this struct below this point.
chainLock sync.RWMutex
// notificationSendLock helps us only process one block at a time.
// It's definitely a hack. DCRD has much better structure in this regard.
// Without this you will get an error if you invalidate a block and then generate more right after.
// Taken from https://github.com/gcash/bchd/pull/308
notificationSendLock sync.Mutex
// These fields are related to the memory block index. They both have
// their own locks, however they are often also protected by the chain
// lock to help prevent logic races when blocks are being processed.
@ -180,6 +190,8 @@ type BlockChain struct {
// certain blockchain events.
notificationsLock sync.RWMutex
notifications []NotificationCallback
claimTrie *claimtrie.ClaimTrie
}
// HaveBlock returns whether or not the chain instance has the block represented
@ -195,6 +207,15 @@ func (b *BlockChain) HaveBlock(hash *chainhash.Hash) (bool, error) {
return exists || b.IsKnownOrphan(hash), nil
}
// GetWarnings returns a bool for whether unknownRules
// has been warned.
func (b *BlockChain) GetWarnings() bool {
b.chainLock.RLock()
defer b.chainLock.RUnlock()
return b.unknownRulesWarned
}
// IsKnownOrphan returns whether the passed hash is currently a known orphan.
// Keep in mind that only a limited number of orphans are held onto for a
// limited amount of time, so this function must not be used as an absolute
@ -468,7 +489,7 @@ func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView
// LockTimeToSequence converts the passed relative locktime to a sequence
// number in accordance to BIP-68.
// See: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
// * (Compatibility)
// - (Compatibility)
func LockTimeToSequence(isSeconds bool, locktime uint32) uint32 {
// If we're expressing the relative lock time in blocks, then the
// corresponding sequence number is simply the desired input age.
@ -571,7 +592,8 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
}
// No warnings about unknown rules until the chain is current.
if b.isCurrent() {
current := b.isCurrent()
if current {
// Warn if any unknown new rules are either about to activate or
// have already been activated.
if err := b.warnUnknownRuleActivations(node); err != nil {
@ -579,6 +601,14 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
}
}
// Handle LBRY Claim Scripts
if b.claimTrie != nil {
shouldFlush := current && b.chainParams.Net != wire.TestNet
if err := b.ParseClaimScripts(block, node, view, shouldFlush); err != nil {
return ruleError(ErrBadClaimTrie, err.Error())
}
}
// Write any block status changes to DB before updating best state.
err := b.index.flushToDB()
if err != nil {
@ -661,9 +691,11 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
// Notify the caller that the block was connected to the main chain.
// The caller would typically want to react with actions such as
// updating wallets.
b.notificationSendLock.Lock()
defer b.notificationSendLock.Unlock()
b.chainLock.Unlock()
defer b.chainLock.Lock()
b.sendNotification(NTBlockConnected, block)
b.chainLock.Lock()
return nil
}
@ -761,6 +793,12 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
return err
}
if b.claimTrie != nil {
if err = b.claimTrie.ResetHeight(node.parent.height); err != nil {
return err
}
}
// Prune fully spent entries and mark all entries in the view unmodified
// now that the modifications have been committed to the database.
view.commit()
@ -780,9 +818,11 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
// Notify the caller that the block was disconnected from the main
// chain. The caller would typically want to react with actions such as
// updating wallets.
b.notificationSendLock.Lock()
defer b.notificationSendLock.Unlock()
b.chainLock.Unlock()
defer b.chainLock.Lock()
b.sendNotification(NTBlockDisconnected, block)
b.chainLock.Lock()
return nil
}
@ -966,6 +1006,7 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error
err = b.checkConnectBlock(n, block, view, nil)
if err != nil {
if _, ok := err.(RuleError); ok {
b.index.UnsetStatusFlags(n, statusValid)
b.index.SetStatusFlags(n, statusValidateFailed)
for de := e.Next(); de != nil; de = de.Next() {
dn := de.Value.(*blockNode)
@ -1067,8 +1108,8 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error
// a reorganization to become the main chain).
//
// The flags modify the behavior of this function as follows:
// - BFFastAdd: Avoids several expensive transaction validation operations.
// This is useful when using checkpoints.
// - BFFastAdd: Avoids several expensive transaction validation operations.
// This is useful when using checkpoints.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, flags BehaviorFlags) (bool, error) {
@ -1103,6 +1144,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
if err == nil {
b.index.SetStatusFlags(node, statusValid)
} else if _, ok := err.(RuleError); ok {
b.index.UnsetStatusFlags(node, statusValid)
b.index.SetStatusFlags(node, statusValidateFailed)
} else {
return false, err
@ -1137,6 +1179,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
// that status of the block as invalid and flush the
// index state to disk before returning with the error.
if _, ok := err.(RuleError); ok {
b.index.UnsetStatusFlags(node, statusValid)
b.index.SetStatusFlags(
node, statusValidateFailed,
)
@ -1207,8 +1250,8 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
// isCurrent returns whether or not the chain believes it is current. Several
// factors are used to guess, but the key factors that allow the chain to
// believe it is current are:
// - Latest block height is after the latest checkpoint (if enabled)
// - Latest block has a timestamp newer than 24 hours ago
// - Latest block height is after the latest checkpoint (if enabled)
// - Latest block has a timestamp newer than ~6 hours ago (as LBRY block time is one fourth of bitcoin)
//
// This function MUST be called with the chain state lock held (for reads).
func (b *BlockChain) isCurrent() bool {
@ -1219,20 +1262,20 @@ func (b *BlockChain) isCurrent() bool {
return false
}
// Not current if the latest best block has a timestamp before 24 hours
// Not current if the latest best block has a timestamp before 7 hours
// ago.
//
// The chain appears to be current if none of the checks reported
// otherwise.
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour).Unix()
return b.bestChain.Tip().timestamp >= minus24Hours
hours := b.timeSource.AdjustedTime().Add(-7 * time.Hour).Unix()
return b.bestChain.Tip().timestamp >= hours
}
// IsCurrent returns whether or not the chain believes it is current. Several
// factors are used to guess, but the key factors that allow the chain to
// believe it is current are:
// - Latest block height is after the latest checkpoint (if enabled)
// - Latest block has a timestamp newer than 24 hours ago
// - Latest block height is after the latest checkpoint (if enabled)
// - Latest block has a timestamp newer than 24 hours ago
//
// This function is safe for concurrent access.
func (b *BlockChain) IsCurrent() bool {
@ -1332,6 +1375,57 @@ func (b *BlockChain) BlockHashByHeight(blockHeight int32) (*chainhash.Hash, erro
return &node.hash, nil
}
// BlockAttributes desribes a Block in relation to others on the main chain.
type BlockAttributes struct {
Height int32
Confirmations int32
MedianTime time.Time
ChainWork *big.Int
PrevHash *chainhash.Hash
NextHash *chainhash.Hash
}
// BlockAttributesByHash returns BlockAttributes for the block with the given hash
// relative to other blocks in the main chain. A BestState snapshot describing
// the main chain is also returned for convenience.
//
// This function is safe for concurrent access.
func (b *BlockChain) BlockAttributesByHash(hash *chainhash.Hash, prevHash *chainhash.Hash) (
attrs *BlockAttributes, best *BestState, err error) {
best = b.BestSnapshot()
node := b.index.LookupNode(hash)
if node == nil {
str := fmt.Sprintf("block %s not found", hash)
return nil, best, errNotInMainChain(str)
}
attrs = &BlockAttributes{
Height: node.height,
Confirmations: 1 + best.Height - node.height,
MedianTime: node.CalcPastMedianTime(),
ChainWork: node.workSum,
}
if !b.bestChain.Contains(node) {
attrs.Confirmations = -1
}
// Populate prev block hash if there is one.
if node.height > 0 {
attrs.PrevHash = prevHash
}
// Populate next block hash if there is one.
if node.height < best.Height {
nextHash, err := b.BlockHashByHeight(node.height + 1)
if err != nil {
return nil, best, err
}
attrs.NextHash = nextHash
}
return attrs, best, nil
}
// HeightRange returns a range of block hashes for the given start and end
// heights. It is inclusive of the start height and exclusive of the end
// height. The end height will be limited to the current main chain height.
@ -1467,11 +1561,11 @@ func (b *BlockChain) IntervalBlockHashes(endHash *chainhash.Hash, interval int,
//
// In addition, there are two special cases:
//
// - When no locators are provided, the stop hash is treated as a request for
// that block, so it will either return the node associated with the stop hash
// if it is known, or nil if it is unknown
// - When locators are provided, but none of them are known, nodes starting
// after the genesis block will be returned
// - When no locators are provided, the stop hash is treated as a request for
// that block, so it will either return the node associated with the stop hash
// if it is known, or nil if it is unknown
// - When locators are provided, but none of them are known, nodes starting
// after the genesis block will be returned
//
// This is primarily a helper function for the locateBlocks and locateHeaders
// functions.
@ -1555,11 +1649,11 @@ func (b *BlockChain) locateBlocks(locator BlockLocator, hashStop *chainhash.Hash
//
// In addition, there are two special cases:
//
// - When no locators are provided, the stop hash is treated as a request for
// that block, so it will either return the stop hash itself if it is known,
// or nil if it is unknown
// - When locators are provided, but none of them are known, hashes starting
// after the genesis block will be returned
// - When no locators are provided, the stop hash is treated as a request for
// that block, so it will either return the stop hash itself if it is known,
// or nil if it is unknown
// - When locators are provided, but none of them are known, hashes starting
// after the genesis block will be returned
//
// This function is safe for concurrent access.
func (b *BlockChain) LocateBlocks(locator BlockLocator, hashStop *chainhash.Hash, maxHashes uint32) []chainhash.Hash {
@ -1600,11 +1694,11 @@ func (b *BlockChain) locateHeaders(locator BlockLocator, hashStop *chainhash.Has
//
// In addition, there are two special cases:
//
// - When no locators are provided, the stop hash is treated as a request for
// that header, so it will either return the header for the stop hash itself
// if it is known, or nil if it is unknown
// - When locators are provided, but none of them are known, headers starting
// after the genesis block will be returned
// - When no locators are provided, the stop hash is treated as a request for
// that header, so it will either return the header for the stop hash itself
// if it is known, or nil if it is unknown
// - When locators are provided, but none of them are known, headers starting
// after the genesis block will be returned
//
// This function is safe for concurrent access.
func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Hash) []wire.BlockHeader {
@ -1614,6 +1708,121 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
return headers
}
// InvalidateBlock takes a block hash and invalidates it.
//
// This function is safe for concurrent access.
func (b *BlockChain) InvalidateBlock(hash *chainhash.Hash) error {
b.chainLock.Lock()
defer b.chainLock.Unlock()
return b.invalidateBlock(hash)
}
// invalidateBlock takes a block hash and invalidates it.
func (b *BlockChain) invalidateBlock(hash *chainhash.Hash) error {
node := b.index.LookupNode(hash)
if node == nil {
err := fmt.Errorf("block %s is not known", hash)
return err
}
// No need to invalidate if its already invalid.
if node.status.KnownInvalid() {
err := fmt.Errorf("block %s is already invalid", hash)
return err
}
if node.parent == nil {
err := fmt.Errorf("block %s has no parent", hash)
return err
}
b.index.SetStatusFlags(node, statusValidateFailed)
b.index.UnsetStatusFlags(node, statusValid)
detachNodes, attachNodes := b.getReorganizeNodes(node.parent)
err := b.reorganizeChain(detachNodes, attachNodes)
if err != nil {
return err
}
for i, e := 0, detachNodes.Front(); e != nil; i, e = i+1, e.Next() {
n := e.Value.(*blockNode)
b.index.SetStatusFlags(n, statusInvalidAncestor)
b.index.UnsetStatusFlags(n, statusValid)
}
if writeErr := b.index.flushToDB(); writeErr != nil {
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
}
return nil
}
// ReconsiderBlock takes a block hash and allows it to be revalidated.
//
// This function is safe for concurrent access.
func (b *BlockChain) ReconsiderBlock(hash *chainhash.Hash) error {
return b.reconsiderBlock(hash)
}
// reconsiderBlock takes a block hash and allows it to be revalidated.
func (b *BlockChain) reconsiderBlock(hash *chainhash.Hash) error {
node := b.index.LookupNode(hash)
if node == nil {
err := fmt.Errorf("block %s is not known", hash)
return err
}
// No need to reconsider, it is already valid.
if node.status.KnownValid() && !node.status.KnownInvalid() { // second clause works around old bug
err := fmt.Errorf("block %s is already valid", hash)
return err
}
// Keep a reference to the first node in the chain of invalid
// blocks so we can reprocess after status flags are updated.
firstNode := node
// Find previous node to the point where the blocks are valid again.
for n := node; n.status.KnownInvalid(); n = n.parent {
b.index.UnsetStatusFlags(n, statusInvalidAncestor)
b.index.UnsetStatusFlags(n, statusValidateFailed)
firstNode = n
}
// do we need an rlock on chainstate for this section?
var blk *btcutil.Block
err := b.db.View(func(dbTx database.Tx) error {
var err error
blk, err = dbFetchBlockByNode(dbTx, firstNode)
return err
})
if err != nil {
return err
}
// Process it all again. This will take care of the
// orphans as well.
_, _, err = b.ProcessBlock(blk, BFNoDupBlockCheck)
if err != nil {
return err
}
if writeErr := b.index.flushToDB(); writeErr != nil {
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
}
return nil
}
// ClaimTrie returns the claimTrie associated wit hthe chain.
func (b *BlockChain) ClaimTrie() *claimtrie.ClaimTrie {
return b.claimTrie
}
// IndexManager provides a generic interface that the is called when blocks are
// connected and disconnected to and from the tip of the main chain for the
// purpose of supporting optional indexes.
@ -1700,6 +1909,8 @@ type Config struct {
// This field can be nil if the caller is not interested in using a
// signature cache.
HashCache *txscript.HashCache
ClaimTrie *claimtrie.ClaimTrie
}
// New returns a BlockChain instance using the provided configuration details.
@ -1736,7 +1947,6 @@ func New(config *Config) (*BlockChain, error) {
params := config.ChainParams
targetTimespan := int64(params.TargetTimespan / time.Second)
targetTimePerBlock := int64(params.TargetTimePerBlock / time.Second)
adjustmentFactor := params.RetargetAdjustmentFactor
b := BlockChain{
checkpoints: config.Checkpoints,
checkpointsByHeight: checkpointsByHeight,
@ -1745,8 +1955,8 @@ func New(config *Config) (*BlockChain, error) {
timeSource: config.TimeSource,
sigCache: config.SigCache,
indexManager: config.IndexManager,
minRetargetTimespan: targetTimespan / adjustmentFactor,
maxRetargetTimespan: targetTimespan * adjustmentFactor,
minRetargetTimespan: targetTimespan - (targetTimespan / 8),
maxRetargetTimespan: targetTimespan + (targetTimespan / 2),
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
index: newBlockIndex(config.DB, params),
hashCache: config.HashCache,
@ -1755,6 +1965,7 @@ func New(config *Config) (*BlockChain, error) {
prevOrphans: make(map[chainhash.Hash][]*orphanBlock),
warningCaches: newThresholdCaches(vbNumBits),
deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments),
claimTrie: config.ClaimTrie,
}
// Initialize the chain state from the passed database. When the db
@ -1764,6 +1975,20 @@ func New(config *Config) (*BlockChain, error) {
return nil, err
}
// Helper function to insert the output in genesis block in to the
// transaction database.
fn := func(dbTx database.Tx) error {
genesisBlock := btcutil.NewBlock(b.chainParams.GenesisBlock)
view := NewUtxoViewpoint()
if err := view.connectTransactions(genesisBlock, nil); err != nil {
return err
}
return dbPutUtxoView(dbTx, view)
}
if err := b.db.Update(fn); err != nil {
return nil, err
}
// Perform any upgrades to the various chain-specific buckets as needed.
if err := b.maybeUpgradeDbBuckets(config.Interrupt); err != nil {
return nil, err
@ -1783,6 +2008,14 @@ func New(config *Config) (*BlockChain, error) {
return nil, err
}
if b.claimTrie != nil {
err := rebuildMissingClaimTrieData(&b, config.Interrupt)
if err != nil {
b.claimTrie.Close()
return nil, err
}
}
bestNode := b.bestChain.Tip()
log.Infof("Chain state (height %d, hash %v, totaltx %d, work %v)",
bestNode.height, bestNode.hash, b.stateSnapshot.TotalTxns,
@ -1790,3 +2023,63 @@ func New(config *Config) (*BlockChain, error) {
return &b, nil
}
func rebuildMissingClaimTrieData(b *BlockChain, done <-chan struct{}) error {
target := b.bestChain.Height()
if b.claimTrie.Height() == target {
return nil
}
if b.claimTrie.Height() > target {
return b.claimTrie.ResetHeight(target)
}
start := time.Now()
lastReport := time.Now()
// TODO: move this view inside the loop (or recreate it every 5 sec.)
// as accumulating all inputs has potential to use a huge amount of RAM
// but we need to get the spent inputs working for that to be possible
view := NewUtxoViewpoint()
for h := int32(0); h < target; h++ {
select {
case <-done:
return fmt.Errorf("rebuild unfinished at height %d", b.claimTrie.Height())
default:
}
n := b.bestChain.NodeByHeight(h + 1)
var block *btcutil.Block
err := b.db.View(func(dbTx database.Tx) error {
var err error
block, err = dbFetchBlockByNode(dbTx, n)
return err
})
if err != nil {
return err
}
err = view.fetchInputUtxos(b.db, block)
if err != nil {
return err
}
err = view.connectTransactions(block, nil)
if err != nil {
return err
}
if h >= b.claimTrie.Height() {
err = b.ParseClaimScripts(block, n, view, false)
if err != nil {
return err
}
}
if time.Since(lastReport) > time.Second*5 {
lastReport = time.Now()
log.Infof("Rebuilding claim trie data to %d. At: %d", target, h)
}
}
log.Infof("Completed rebuilding claim trie data to %d. Took %s ",
b.claimTrie.Height(), time.Since(start))
return nil
}

View file

@ -9,108 +9,12 @@ import (
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
// TestHaveBlock tests the HaveBlock API to ensure proper functionality.
func TestHaveBlock(t *testing.T) {
// Load up blocks such that there is a side chain.
// (genesis block) -> 1 -> 2 -> 3 -> 4
// \-> 3a
testFiles := []string{
"blk_0_to_4.dat.bz2",
"blk_3A.dat.bz2",
}
var blocks []*btcutil.Block
for _, file := range testFiles {
blockTmp, err := loadBlocks(file)
if err != nil {
t.Errorf("Error loading file: %v\n", err)
return
}
blocks = append(blocks, blockTmp...)
}
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("haveblock",
&chaincfg.MainNetParams)
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return
}
defer teardownFunc()
// Since we're not dealing with the real block chain, set the coinbase
// maturity to 1.
chain.TstSetCoinbaseMaturity(1)
for i := 1; i < len(blocks); i++ {
_, isOrphan, err := chain.ProcessBlock(blocks[i], BFNone)
if err != nil {
t.Errorf("ProcessBlock fail on block %v: %v\n", i, err)
return
}
if isOrphan {
t.Errorf("ProcessBlock incorrectly returned block %v "+
"is an orphan\n", i)
return
}
}
// Insert an orphan block.
_, isOrphan, err := chain.ProcessBlock(btcutil.NewBlock(&Block100000),
BFNone)
if err != nil {
t.Errorf("Unable to process block: %v", err)
return
}
if !isOrphan {
t.Errorf("ProcessBlock indicated block is an not orphan when " +
"it should be\n")
return
}
tests := []struct {
hash string
want bool
}{
// Genesis block should be present (in the main chain).
{hash: chaincfg.MainNetParams.GenesisHash.String(), want: true},
// Block 3a should be present (on a side chain).
{hash: "00000000474284d20067a4d33f6a02284e6ef70764a3a26d6a5b9df52ef663dd", want: true},
// Block 100000 should be present (as an orphan).
{hash: "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506", want: true},
// Random hashes should not be available.
{hash: "123", want: false},
}
for i, test := range tests {
hash, err := chainhash.NewHashFromStr(test.hash)
if err != nil {
t.Errorf("NewHashFromStr: %v", err)
continue
}
result, err := chain.HaveBlock(hash)
if err != nil {
t.Errorf("HaveBlock #%d unexpected error: %v", i, err)
return
}
if result != test.want {
t.Errorf("HaveBlock #%d got %v want %v", i, result,
test.want)
continue
}
}
}
// TestCalcSequenceLock tests the LockTimeToSequence function, and the
// CalcSequenceLock method of a Chain instance. The tests exercise several
// combinations of inputs to the CalcSequenceLock function in order to ensure

View file

@ -12,10 +12,10 @@ import (
"sync"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
const (

View file

@ -11,8 +11,8 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/wire"
)
// TestErrNotInMainChain ensures the functions related to errNotInMainChain work

123
blockchain/chainquery.go Normal file
View file

@ -0,0 +1,123 @@
package blockchain
import (
"sort"
"strings"
btcutil "github.com/lbryio/lbcutil"
)
type ChainTip struct { // duplicate of btcjson.GetChainTipsResult to avoid circular reference
Height int64
Hash string
BranchLen int64
Status string
}
// nodeHeightSorter implements sort.Interface to allow a slice of nodes to
// be sorted by height in ascending order.
type nodeHeightSorter []ChainTip
// Len returns the number of nodes in the slice. It is part of the
// sort.Interface implementation.
func (s nodeHeightSorter) Len() int {
return len(s)
}
// Swap swaps the nodes at the passed indices. It is part of the
// sort.Interface implementation.
func (s nodeHeightSorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// Less returns whether the node with index i should sort before the node with
// index j. It is part of the sort.Interface implementation.
func (s nodeHeightSorter) Less(i, j int) bool {
// To ensure stable order when the heights are the same, fall back to
// sorting based on hash.
if s[i].Height == s[j].Height {
return strings.Compare(s[i].Hash, s[j].Hash) < 0
}
return s[i].Height < s[j].Height
}
// ChainTips returns information, in JSON-RPC format, about all the currently
// known chain tips in the block index.
func (b *BlockChain) ChainTips() []ChainTip {
// we need our current tip
// we also need all of our orphans that aren't in the prevOrphans
var results []ChainTip
tip := b.bestChain.Tip()
results = append(results, ChainTip{
Height: int64(tip.height),
Hash: tip.hash.String(),
BranchLen: 0,
Status: "active",
})
b.orphanLock.RLock()
defer b.orphanLock.RUnlock()
notInBestChain := func(block *btcutil.Block) bool {
node := b.bestChain.NodeByHeight(block.Height())
if node == nil {
return false
}
return node.hash.IsEqual(block.Hash())
}
for hash, orphan := range b.orphans {
if len(b.prevOrphans[hash]) > 0 {
continue
}
fork := orphan.block
for fork != nil && notInBestChain(fork) {
fork = b.orphans[*fork.Hash()].block
}
result := ChainTip{
Height: int64(orphan.block.Height()),
Hash: hash.String(),
BranchLen: int64(orphan.block.Height() - fork.Height()),
}
// Determine the status of the chain tip.
//
// active:
// The current best chain tip.
//
// invalid:
// The block or one of its ancestors is invalid.
//
// headers-only:
// The block or one of its ancestors does not have the full block data
// available which also means the block can't be validated or
// connected.
//
// valid-fork:
// The block is fully validated which implies it was probably part of
// main chain at one point and was reorganized.
//
// valid-headers:
// The full block data is available and the header is valid, but the
// block was never validated which implies it was probably never part
// of the main chain.
tipStatus := b.index.LookupNode(&hash).status
if tipStatus.KnownInvalid() {
result.Status = "invalid"
} else if !tipStatus.HaveData() {
result.Status = "headers-only"
} else if tipStatus.KnownValid() {
result.Status = "valid-fork"
} else {
result.Status = "valid-headers"
}
results = append(results, result)
}
// Generate the results sorted by descending height.
sort.Sort(sort.Reverse(nodeHeightSorter(results)))
return results
}

View file

@ -36,11 +36,13 @@ func fastLog2Floor(n uint32) uint8 {
// for comparing chains.
//
// For example, assume a block chain with a side chain as depicted below:
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
// \-> 4a -> 5a -> 6a
//
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
// \-> 4a -> 5a -> 6a
//
// The chain view for the branch ending in 6a consists of:
// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a
//
// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a
type chainView struct {
mtx sync.Mutex
nodes []*blockNode
@ -258,12 +260,14 @@ func (c *chainView) next(node *blockNode) *blockNode {
// view.
//
// For example, assume a block chain with a side chain as depicted below:
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
// \-> 4a -> 5a -> 6a
//
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
// \-> 4a -> 5a -> 6a
//
// Further, assume the view is for the longer chain depicted above. That is to
// say it consists of:
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
//
// genesis -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
//
// Invoking this function with block node 5 would return block node 6 while
// invoking it with block node 5a would return nil since that node is not part
@ -321,12 +325,14 @@ func (c *chainView) findFork(node *blockNode) *blockNode {
// the chain view. It will return nil if there is no common block.
//
// For example, assume a block chain with a side chain as depicted below:
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8
// \-> 6a -> 7a
//
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8
// \-> 6a -> 7a
//
// Further, assume the view is for the longer chain depicted above. That is to
// say it consists of:
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8.
//
// genesis -> 1 -> 2 -> ... -> 5 -> 6 -> 7 -> 8.
//
// Invoking this function with block node 7a would return block node 5 while
// invoking it with block node 7 would return itself since it is already part of

View file

@ -10,7 +10,7 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
// testNoncePrng provides a deterministic prng for the nonce in generated fake

View file

@ -8,10 +8,10 @@ import (
"fmt"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
btcutil "github.com/lbryio/lbcutil"
)
// CheckpointConfirmations is the number of blocks before the end of the current
@ -172,7 +172,8 @@ func (b *BlockChain) findPreviousCheckpoint() (*blockNode, error) {
func isNonstandardTransaction(tx *btcutil.Tx) bool {
// Check all of the output public key scripts for non-standard scripts.
for _, txOut := range tx.MsgTx().TxOut {
scriptClass := txscript.GetScriptClass(txOut.PkScript)
stripped := txscript.StripClaimScriptPrefix(txOut.PkScript)
scriptClass := txscript.GetScriptClass(stripped)
if scriptClass == txscript.NonStandardTy {
return true
}
@ -184,14 +185,14 @@ func isNonstandardTransaction(tx *btcutil.Tx) bool {
// checkpoint candidate.
//
// The factors used to determine a good checkpoint are:
// - The block must be in the main chain
// - The block must be at least 'CheckpointConfirmations' blocks prior to the
// current end of the main chain
// - The timestamps for the blocks before and after the checkpoint must have
// timestamps which are also before and after the checkpoint, respectively
// (due to the median time allowance this is not always the case)
// - The block must not contain any strange transaction such as those with
// nonstandard scripts
// - The block must be in the main chain
// - The block must be at least 'CheckpointConfirmations' blocks prior to the
// current end of the main chain
// - The timestamps for the blocks before and after the checkpoint must have
// timestamps which are also before and after the checkpoint, respectively
// (due to the median time allowance this is not always the case)
// - The block must not contain any strange transaction such as those with
// nonstandard scripts
//
// The intent is that candidates are reviewed by a developer to make the final
// decision and then manually added to the list of checkpoints for a network.

183
blockchain/claimtrie.go Normal file
View file

@ -0,0 +1,183 @@
package blockchain
import (
"bytes"
"fmt"
"github.com/pkg/errors"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
"github.com/lbryio/lbcd/claimtrie"
"github.com/lbryio/lbcd/claimtrie/change"
"github.com/lbryio/lbcd/claimtrie/node"
"github.com/lbryio/lbcd/claimtrie/normalization"
)
func (b *BlockChain) SetClaimtrieHeader(block *btcutil.Block, view *UtxoViewpoint) error {
b.chainLock.Lock()
defer b.chainLock.Unlock()
err := b.ParseClaimScripts(block, nil, view, false)
if err != nil {
return errors.Wrapf(err, "in parse claim scripts")
}
block.MsgBlock().Header.ClaimTrie = *b.claimTrie.MerkleHash()
err = b.claimTrie.ResetHeight(b.claimTrie.Height() - 1)
return errors.Wrapf(err, "in reset height")
}
func (b *BlockChain) ParseClaimScripts(block *btcutil.Block, bn *blockNode, view *UtxoViewpoint, shouldFlush bool) error {
ht := block.Height()
for _, tx := range block.Transactions() {
h := handler{ht, tx, view, map[string][]byte{}}
if err := h.handleTxIns(b.claimTrie); err != nil {
return err
}
if err := h.handleTxOuts(b.claimTrie); err != nil {
return err
}
}
err := b.claimTrie.AppendBlock(bn == nil)
if err != nil {
return errors.Wrapf(err, "in append block")
}
if shouldFlush {
b.claimTrie.FlushToDisk()
}
hash := b.claimTrie.MerkleHash()
if bn != nil && bn.claimTrie != *hash {
// undo our AppendBlock call as we've decided that our interpretation of the block data is incorrect,
// or that the person who made the block assembled the pieces incorrectly.
_ = b.claimTrie.ResetHeight(b.claimTrie.Height() - 1)
return errors.Errorf("height: %d, computed hash: %s != header's ClaimTrie: %s", ht, *hash, bn.claimTrie)
}
return nil
}
type handler struct {
ht int32
tx *btcutil.Tx
view *UtxoViewpoint
spent map[string][]byte
}
func (h *handler) handleTxIns(ct *claimtrie.ClaimTrie) error {
if IsCoinBase(h.tx) {
return nil
}
for _, txIn := range h.tx.MsgTx().TxIn {
op := txIn.PreviousOutPoint
e := h.view.LookupEntry(op)
if e == nil {
return errors.Errorf("missing input in view for %s", op.String())
}
cs, err := txscript.ExtractClaimScript(e.pkScript)
if txscript.IsErrorCode(err, txscript.ErrNotClaimScript) {
continue
}
if err != nil {
return err
}
var id change.ClaimID
name := cs.Name // name of the previous one (that we're now spending)
switch cs.Opcode {
case txscript.OP_CLAIMNAME: // OP code from previous transaction
id = change.NewClaimID(op) // claimID of the previous item now being spent
h.spent[id.Key()] = normalization.NormalizeIfNecessary(name, ct.Height())
err = ct.SpendClaim(name, op, id)
case txscript.OP_UPDATECLAIM:
copy(id[:], cs.ClaimID)
h.spent[id.Key()] = normalization.NormalizeIfNecessary(name, ct.Height())
err = ct.SpendClaim(name, op, id)
case txscript.OP_SUPPORTCLAIM:
copy(id[:], cs.ClaimID)
err = ct.SpendSupport(name, op, id)
}
if err != nil {
return errors.Wrapf(err, "handleTxIns")
}
}
return nil
}
func (h *handler) handleTxOuts(ct *claimtrie.ClaimTrie) error {
for i, txOut := range h.tx.MsgTx().TxOut {
op := *wire.NewOutPoint(h.tx.Hash(), uint32(i))
cs, err := txscript.ExtractClaimScript(txOut.PkScript)
if txscript.IsErrorCode(err, txscript.ErrNotClaimScript) {
continue
}
if err != nil {
return err
}
var id change.ClaimID
name := cs.Name
amt := txOut.Value
switch cs.Opcode {
case txscript.OP_CLAIMNAME:
id = change.NewClaimID(op)
err = ct.AddClaim(name, op, id, amt)
case txscript.OP_SUPPORTCLAIM:
copy(id[:], cs.ClaimID)
err = ct.AddSupport(name, op, amt, id)
case txscript.OP_UPDATECLAIM:
// old code wouldn't run the update if name or claimID didn't match existing data
// that was a safety feature, but it should have rejected the transaction instead
// TODO: reject transactions with invalid update commands
copy(id[:], cs.ClaimID)
normName := normalization.NormalizeIfNecessary(name, ct.Height())
if !bytes.Equal(h.spent[id.Key()], normName) {
node.LogOnce(fmt.Sprintf("Invalid update operation: name or ID mismatch at %d for: %s, %s",
ct.Height(), normName, id.String()))
continue
}
delete(h.spent, id.Key())
err = ct.UpdateClaim(name, op, amt, id)
}
if err != nil {
return errors.Wrapf(err, "handleTxOuts")
}
}
return nil
}
func (b *BlockChain) GetNamesChangedInBlock(height int32) ([]string, error) {
b.chainLock.RLock()
defer b.chainLock.RUnlock()
return b.claimTrie.NamesChangedInBlock(height)
}
func (b *BlockChain) GetClaimsForName(height int32, name string) (string, *node.Node, error) {
normalizedName := normalization.NormalizeIfNecessary([]byte(name), height)
b.chainLock.RLock()
defer b.chainLock.RUnlock()
n, err := b.claimTrie.NodeAt(height, normalizedName)
if err != nil {
return string(normalizedName), nil, err
}
if n == nil {
return string(normalizedName), nil, fmt.Errorf("name does not exist at height %d: %s", height, name)
}
n.SortClaimsByBid()
return string(normalizedName), n, nil
}

View file

@ -5,6 +5,7 @@
package blockchain
import (
"bytes"
"compress/bzip2"
"encoding/binary"
"fmt"
@ -14,13 +15,13 @@ import (
"strings"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
_ "github.com/btcsuite/btcd/database/ffldb"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
_ "github.com/lbryio/lbcd/database/ffldb"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
const (
@ -63,13 +64,13 @@ func isSupportedDbType(dbType string) bool {
func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
filename = filepath.Join("testdata/", filename)
var network = wire.MainNet
var network = 0xd9b4bef9 // bitcoin's network ID
var dr io.Reader
var fi io.ReadCloser
fi, err = os.Open(filename)
if err != nil {
return
return blocks, err
}
if strings.HasSuffix(filename, ".bz2") {
@ -95,7 +96,7 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
break
}
if rintbuf != uint32(network) {
break
continue
}
err = binary.Read(dr, binary.LittleEndian, &rintbuf)
blocklen := rintbuf
@ -105,14 +106,20 @@ func loadBlocks(filename string) (blocks []*btcutil.Block, err error) {
// read block
dr.Read(rbytes)
// inject claimtrie:
tail := make([]byte, len(rbytes)-68)
copy(tail, rbytes[68:])
rbytes = append(rbytes[:68], bytes.Repeat([]byte{23}, chainhash.HashSize)...)
rbytes = append(rbytes, tail...)
block, err = btcutil.NewBlockFromBytes(rbytes)
if err != nil {
return
return blocks, err
}
blocks = append(blocks, block)
}
return
return blocks, err
}
// chainSetup is used to create a new db and chain instance with the genesis

View file

@ -5,8 +5,8 @@
package blockchain
import (
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/btcec"
"github.com/lbryio/lbcd/txscript"
)
// -----------------------------------------------------------------------------

View file

@ -8,7 +8,7 @@ import (
"math/big"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/chaincfg/chainhash"
)
var (
@ -42,18 +42,21 @@ func HashToBig(hash *chainhash.Hash) *big.Int {
// Like IEEE754 floating point, there are three basic components: the sign,
// the exponent, and the mantissa. They are broken out as follows:
//
// * the most significant 8 bits represent the unsigned base 256 exponent
// * bit 23 (the 24th bit) represents the sign bit
// * the least significant 23 bits represent the mantissa
// - the most significant 8 bits represent the unsigned base 256 exponent
//
// -------------------------------------------------
// | Exponent | Sign | Mantissa |
// -------------------------------------------------
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
// -------------------------------------------------
// - bit 23 (the 24th bit) represents the sign bit
//
// - the least significant 23 bits represent the mantissa
//
// -------------------------------------------------
// | Exponent | Sign | Mantissa |
// -------------------------------------------------
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
// -------------------------------------------------
//
// The formula to calculate N is:
// N = (-1^sign) * mantissa * 256^(exponent-3)
//
// N = (-1^sign) * mantissa * 256^(exponent-3)
//
// This compact form is only used in bitcoin to encode unsigned 256-bit numbers
// which represent difficulty targets, thus there really is not a need for a
@ -159,7 +162,6 @@ func CalcWork(bits uint32) *big.Int {
func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
// Convert types used in the calculations below.
durationVal := int64(duration / time.Second)
adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
// The test network rules allow minimum difficulty blocks after more
// than twice the desired amount of time needed to generate a block has
@ -178,7 +180,8 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration)
// multiplied by the max adjustment factor.
newTarget := CompactToBig(bits)
for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 {
newTarget.Mul(newTarget, adjustmentFactor)
adj := new(big.Int).Div(newTarget, big.NewInt(2))
newTarget.Add(newTarget, adj)
durationVal -= b.maxRetargetTimespan
}
@ -224,47 +227,45 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
return b.chainParams.PowLimitBits, nil
}
// Return the previous block's difficulty requirements if this block
// is not at a difficulty retarget interval.
if (lastNode.height+1)%b.blocksPerRetarget != 0 {
// For networks that support it, allow special reduction of the
// required difficulty once too much time has elapsed without
// mining a block.
if b.chainParams.ReduceMinDifficulty {
// Return minimum difficulty when more than the desired
// amount of time has elapsed without mining a block.
reductionTime := int64(b.chainParams.MinDiffReductionTime /
time.Second)
allowMinTime := lastNode.timestamp + reductionTime
if newBlockTime.Unix() > allowMinTime {
return b.chainParams.PowLimitBits, nil
}
// The block was mined within the desired timeframe, so
// return the difficulty for the last block which did
// not have the special minimum difficulty rule applied.
return b.findPrevTestNetDifficulty(lastNode), nil
// For networks that support it, allow special reduction of the
// required difficulty once too much time has elapsed without
// mining a block.
if b.chainParams.ReduceMinDifficulty {
// Return minimum difficulty when more than the desired
// amount of time has elapsed without mining a block.
reductionTime := int64(b.chainParams.MinDiffReductionTime /
time.Second)
allowMinTime := lastNode.timestamp + reductionTime
if newBlockTime.Unix() > allowMinTime {
return b.chainParams.PowLimitBits, nil
}
// For the main network (or any unrecognized networks), simply
// return the previous block's difficulty requirements.
return lastNode.bits, nil
// The block was mined within the desired timeframe, so
// return the difficulty for the last block which did
// not have the special minimum difficulty rule applied.
return b.findPrevTestNetDifficulty(lastNode), nil
}
// Get the block node at the previous retarget (targetTimespan days
// worth of blocks).
firstNode := lastNode.RelativeAncestor(b.blocksPerRetarget - 1)
blocksBack := b.blocksPerRetarget
if blocksBack > lastNode.height {
blocksBack = lastNode.height
}
firstNode := lastNode.RelativeAncestor(blocksBack)
if firstNode == nil {
return 0, AssertError("unable to obtain previous retarget block")
}
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
// Limit the amount of adjustment that can occur to the previous
// difficulty.
actualTimespan := lastNode.timestamp - firstNode.timestamp
adjustedTimespan := actualTimespan
if actualTimespan < b.minRetargetTimespan {
adjustedTimespan := targetTimeSpan + (actualTimespan-targetTimeSpan)/8
if adjustedTimespan < b.minRetargetTimespan {
adjustedTimespan = b.minRetargetTimespan
} else if actualTimespan > b.maxRetargetTimespan {
} else if adjustedTimespan > b.maxRetargetTimespan {
adjustedTimespan = b.maxRetargetTimespan
}
@ -275,7 +276,6 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
// result.
oldTarget := CompactToBig(lastNode.bits)
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))
targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)
newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
// Limit new value to the proof of work limit.

View file

@ -26,42 +26,42 @@ caller a high level of flexibility in how they want to react to certain events
such as orphan blocks which need their parents requested and newly connected
main chain blocks which might result in wallet updates.
Bitcoin Chain Processing Overview
# Bitcoin Chain Processing Overview
Before a block is allowed into the block chain, it must go through an intensive
series of validation rules. The following list serves as a general outline of
those rules to provide some intuition into what is going on under the hood, but
is by no means exhaustive:
- Reject duplicate blocks
- Perform a series of sanity checks on the block and its transactions such as
verifying proof of work, timestamps, number and character of transactions,
transaction amounts, script complexity, and merkle root calculations
- Compare the block against predetermined checkpoints for expected timestamps
and difficulty based on elapsed time since the checkpoint
- Save the most recent orphan blocks for a limited time in case their parent
blocks become available
- Stop processing if the block is an orphan as the rest of the processing
depends on the block's position within the block chain
- Perform a series of more thorough checks that depend on the block's position
within the block chain such as verifying block difficulties adhere to
difficulty retarget rules, timestamps are after the median of the last
several blocks, all transactions are finalized, checkpoint blocks match, and
block versions are in line with the previous blocks
- Determine how the block fits into the chain and perform different actions
accordingly in order to ensure any side chains which have higher difficulty
than the main chain become the new main chain
- When a block is being connected to the main chain (either through
reorganization of a side chain to the main chain or just extending the
main chain), perform further checks on the block's transactions such as
verifying transaction duplicates, script complexity for the combination of
connected scripts, coinbase maturity, double spends, and connected
transaction values
- Run the transaction scripts to verify the spender is allowed to spend the
coins
- Insert the block into the block database
- Reject duplicate blocks
- Perform a series of sanity checks on the block and its transactions such as
verifying proof of work, timestamps, number and character of transactions,
transaction amounts, script complexity, and merkle root calculations
- Compare the block against predetermined checkpoints for expected timestamps
and difficulty based on elapsed time since the checkpoint
- Save the most recent orphan blocks for a limited time in case their parent
blocks become available
- Stop processing if the block is an orphan as the rest of the processing
depends on the block's position within the block chain
- Perform a series of more thorough checks that depend on the block's position
within the block chain such as verifying block difficulties adhere to
difficulty retarget rules, timestamps are after the median of the last
several blocks, all transactions are finalized, checkpoint blocks match, and
block versions are in line with the previous blocks
- Determine how the block fits into the chain and perform different actions
accordingly in order to ensure any side chains which have higher difficulty
than the main chain become the new main chain
- When a block is being connected to the main chain (either through
reorganization of a side chain to the main chain or just extending the
main chain), perform further checks on the block's transactions such as
verifying transaction duplicates, script complexity for the combination of
connected scripts, coinbase maturity, double spends, and connected
transaction values
- Run the transaction scripts to verify the spender is allowed to spend the
coins
- Insert the block into the block database
Errors
# Errors
Errors returned by this package are either the raw errors provided by underlying
calls or of type blockchain.RuleError. This allows the caller to differentiate
@ -70,12 +70,12 @@ violations through type assertions. In addition, callers can programmatically
determine the specific rule violation by examining the ErrorCode field of the
type asserted blockchain.RuleError.
Bitcoin Improvement Proposals
# Bitcoin Improvement Proposals
This package includes spec changes outlined by the following BIPs:
BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)
BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)
*/
package blockchain

View file

@ -220,6 +220,10 @@ const (
// current chain tip. This is not a block validation rule, but is required
// for block proposals submitted via getblocktemplate RPC.
ErrPrevBlockNotBest
// ErrBadClaimTrie indicates the calculated ClaimTrie root does not match
// the expected value.
ErrBadClaimTrie
)
// Map of ErrorCode values back to their constant names for pretty printing.
@ -267,6 +271,7 @@ var errorCodeStrings = map[ErrorCode]string{
ErrPreviousBlockUnknown: "ErrPreviousBlockUnknown",
ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock",
ErrPrevBlockNotBest: "ErrPrevBlockNotBest",
ErrBadClaimTrie: "ErrBadClaimTrie",
}
// String returns the ErrorCode as a human-readable name.

View file

@ -10,11 +10,11 @@ import (
"os"
"path/filepath"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/database"
_ "github.com/btcsuite/btcd/database/ffldb"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/database"
_ "github.com/lbryio/lbcd/database/ffldb"
btcutil "github.com/lbryio/lbcutil"
)
// This example demonstrates how to create a new chain instance and use
@ -69,7 +69,7 @@ func ExampleBlockChain_ProcessBlock() {
fmt.Printf("Block accepted. Is it an orphan?: %v", isOrphan)
// Output:
// Failed to process block: already have block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
// Failed to process block: already have block 9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463
}
// This example demonstrates how to convert the compact "bits" in a block header

View file

@ -12,15 +12,15 @@ import (
"path/filepath"
"testing"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/blockchain/fullblocktests"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
_ "github.com/btcsuite/btcd/database/ffldb"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/blockchain/fullblocktests"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
_ "github.com/lbryio/lbcd/database/ffldb"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
const (
@ -139,7 +139,7 @@ func TestFullBlocks(t *testing.T) {
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("fullblocktest",
&chaincfg.RegressionNetParams)
fullblocktests.FbRegressionNetParams)
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return

View file

@ -1,9 +1,9 @@
fullblocktests
==============
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/fullblocktests)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/fullblocktests)
Package fullblocktests provides a set of full block tests to be used for testing
the consensus validation rules. The tests are intended to be flexible enough to
@ -20,7 +20,7 @@ of blocks that exercise the consensus validation rules.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/blockchain/fullblocktests
$ go get -u github.com/lbryio/lbcd/blockchain/fullblocktests
```
## License

View file

@ -18,24 +18,24 @@ import (
"runtime"
"time"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/btcec"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
const (
// Intentionally defined here rather than using constants from codebase
// to ensure consensus changes are detected.
maxBlockSigOps = 20000
maxBlockSize = 1000000
maxBlockSize = 8000000
minCoinbaseScriptLen = 2
maxCoinbaseScriptLen = 100
medianTimeBlocks = 11
maxScriptElementSize = 520
maxScriptElementSize = 20000
// numLargeReorgBlocks is the number of blocks to use in the large block
// reorg test (when enabled). This is the equivalent of 1 week's worth
@ -342,10 +342,8 @@ func solveBlock(header *wire.BlockHeader) bool {
return
default:
hdr.Nonce = i
hash := hdr.BlockHash()
if blockchain.HashToBig(&hash).Cmp(
targetDifficulty) <= 0 {
hash := hdr.BlockPoWHash()
if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
results <- sbResult{true, i}
return
}
@ -466,9 +464,9 @@ func createSpendTxForTx(tx *wire.MsgTx, fee btcutil.Amount) *wire.MsgTx {
// - A coinbase that pays the required subsidy to an OP_TRUE script
// - When a spendable output is provided:
// - A transaction that spends from the provided output the following outputs:
// - One that pays the inputs amount minus 1 atom to an OP_TRUE script
// - One that contains an OP_RETURN output with a random uint64 in order to
// ensure the transaction has a unique hash
// - One that pays the inputs amount minus 1 atom to an OP_TRUE script
// - One that contains an OP_RETURN output with a random uint64 in order to
// ensure the transaction has a unique hash
//
// Additionally, if one or more munge functions are specified, they will be
// invoked with the block prior to solving it. This provides callers with the
@ -811,7 +809,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// Create a test generator instance initialized with the genesis block
// as the tip.
g, err := makeTestGenerator(regressionNetParams)
g, err := makeTestGenerator(FbRegressionNetParams)
if err != nil {
return nil, err
}
@ -1444,7 +1442,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
// Keep incrementing the nonce until the hash treated as
// a uint256 is higher than the limit.
b46.Header.Nonce++
blockHash := b46.BlockHash()
blockHash := b46.Header.BlockPoWHash()
hashNum := blockchain.HashToBig(&blockHash)
if hashNum.Cmp(g.params.PowLimit) >= 0 {
break
@ -1875,7 +1873,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
//
// Comment assumptions:
// maxBlockSigOps = 20000
// maxScriptElementSize = 520
// maxScriptElementSize = 20000
//
// [0-19999] : OP_CHECKSIG
// [20000] : OP_PUSHDATA4

View file

@ -9,9 +9,9 @@ import (
"math/big"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
)
// newHashFromStr converts the passed big-endian hex string into a
@ -54,6 +54,7 @@ var (
Version: 1,
PrevBlock: *newHashFromStr("0000000000000000000000000000000000000000000000000000000000000000"),
MerkleRoot: *newHashFromStr("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"),
ClaimTrie: chainhash.Hash{1}, // EmptyTrieHash
Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC
Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000]
Nonce: 2,
@ -83,23 +84,25 @@ var (
LockTime: 0,
}},
}
regTestGenesisBlockHash = regTestGenesisBlock.BlockHash()
)
// regressionNetParams defines the network parameters for the regression test
// FbRegressionNetParams defines the network parameters for the regression test
// network.
//
// NOTE: The test generator intentionally does not use the existing definitions
// in the chaincfg package since the intent is to be able to generate known
// good tests which exercise that code. Using the chaincfg parameters would
// allow them to change out from under the tests potentially invalidating them.
var regressionNetParams = &chaincfg.Params{
var FbRegressionNetParams = &chaincfg.Params{
Name: "regtest",
Net: wire.TestNet,
DefaultPort: "18444",
// Chain parameters
GenesisBlock: &regTestGenesisBlock,
GenesisHash: newHashFromStr("5bec7567af40504e0994db3b573c186fffcc4edefe096ff2e58d00523bd7e8a6"),
GenesisHash: &regTestGenesisBlockHash,
PowLimit: regressionPowLimit,
PowLimitBits: 0x207fffff,
CoinbaseMaturity: 100,
@ -113,6 +116,7 @@ var regressionNetParams = &chaincfg.Params{
ReduceMinDifficulty: true,
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
GenerateSupported: true,
MinerConfirmationWindow: 1,
// Checkpoints ordered from oldest to newest.
Checkpoints: nil,

View file

@ -1,9 +1,9 @@
indexers
========
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![Build Status](https://github.com/lbryio/lbcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/lbryio/lbcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/indexers?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/blockchain/indexers)
[![GoDoc](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/indexers?status.png)](https://pkg.go.dev/github.com/lbryio/lbcd/blockchain/indexers)
Package indexers implements optional block chain indexes.
@ -23,7 +23,7 @@ via an RPC interface.
## Installation
```bash
$ go get -u github.com/btcsuite/btcd/blockchain/indexers
$ go get -u github.com/lbryio/lbcd/blockchain/indexers
```
## License

View file

@ -9,13 +9,13 @@ import (
"fmt"
"sync"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
const (

View file

@ -9,7 +9,7 @@ import (
"fmt"
"testing"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
// addrIndexBucket provides a mock address index database bucket by implementing

View file

@ -9,7 +9,7 @@ import (
"time"
"github.com/btcsuite/btclog"
"github.com/btcsuite/btcutil"
btcutil "github.com/lbryio/lbcutil"
)
// blockProgressLogger provides periodic logging for other services in order
@ -27,8 +27,9 @@ type blockProgressLogger struct {
// newBlockProgressLogger returns a new block progress logger.
// The progress message is templated as follows:
// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod}
// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp})
//
// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod}
// ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp})
func newBlockProgressLogger(progressMessage string, logger btclog.Logger) *blockProgressLogger {
return &blockProgressLogger{
lastBlockLogTime: time.Now(),

View file

@ -7,14 +7,14 @@ package indexers
import (
"errors"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/gcs"
"github.com/btcsuite/btcutil/gcs/builder"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
"github.com/lbryio/lbcutil/gcs"
"github.com/lbryio/lbcutil/gcs/builder"
)
const (

View file

@ -11,9 +11,9 @@ import (
"encoding/binary"
"errors"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/database"
btcutil "github.com/lbryio/lbcutil"
)
var (

View file

@ -8,11 +8,11 @@ import (
"bytes"
"fmt"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
var (

View file

@ -8,11 +8,11 @@ import (
"errors"
"fmt"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/blockchain"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
const (

View file

@ -183,7 +183,7 @@ func (m *medianTime) AddTimeSample(sourceID string, timeVal time.Time) {
// Warn if none of the time samples are close.
if !remoteHasCloseTime {
log.Warnf("Please check your date and time " +
"are correct! btcd will not work " +
"are correct! lbcd will not work " +
"properly with an invalid time")
}
}

View file

@ -9,9 +9,10 @@ import (
"fmt"
"math"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
const (
@ -86,7 +87,7 @@ func HashMerkleBranches(left *chainhash.Hash, right *chainhash.Hash) *chainhash.
//
// The above stored as a linear array is as follows:
//
// [h1 h2 h3 h4 h12 h34 root]
// [h1 h2 h3 h4 h12 h34 root]
//
// As the above shows, the merkle root is always the last element in the array.
//
@ -227,11 +228,25 @@ func ValidateWitnessCommitment(blk *btcutil.Block) error {
// coinbase transaction MUST have exactly one witness element within
// its witness data and that element must be exactly
// CoinbaseWitnessDataLen bytes.
//
// Some popular pool software, for example yiimp, uses pre-BIP0141
// coinbase struture. In this case, we don't just accept it, but also
// turn it into post-BIP0141 format.
if len(coinbaseTx.MsgTx().TxIn[0].Witness) == 0 {
log.Infof("pre-BIP0141 coinbase transaction detected. Height: %d", blk.Height())
var witnessNonce [CoinbaseWitnessDataLen]byte
coinbaseTx.MsgTx().TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
blk.MsgBlock().Transactions[0].TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
// Clear cached serialized block.
blk.SetBytes(nil)
}
coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness
if len(coinbaseWitness) != 1 {
str := fmt.Sprintf("the coinbase transaction has %d items in "+
"its witness stack when only one is allowed",
len(coinbaseWitness))
"its witness stack when only one is allowed. Height: %d",
len(coinbaseWitness), blk.Height())
return ruleError(ErrInvalidWitnessCommitment, str)
}
witnessNonce := coinbaseWitness[0]

View file

@ -6,16 +6,14 @@ package blockchain
import (
"testing"
"github.com/btcsuite/btcutil"
)
// TestMerkle tests the BuildMerkleTreeStore API.
func TestMerkle(t *testing.T) {
block := btcutil.NewBlock(&Block100000)
block := GetBlock100000()
merkles := BuildMerkleTreeStore(block.Transactions(), false)
calculatedMerkleRoot := merkles[len(merkles)-1]
wantMerkle := &Block100000.Header.MerkleRoot
wantMerkle := block.MsgBlock().Header.MerkleRoot
if !wantMerkle.IsEqual(calculatedMerkleRoot) {
t.Errorf("BuildMerkleTreeStore: merkle root mismatch - "+
"got %v, want %v", calculatedMerkleRoot, wantMerkle)

View file

@ -50,9 +50,9 @@ func (n NotificationType) String() string {
// Notification defines notification that is sent to the caller via the callback
// function provided during the call to New and consists of a notification type
// as well as associated data that depends on the type as follows:
// - NTBlockAccepted: *btcutil.Block
// - NTBlockConnected: *btcutil.Block
// - NTBlockDisconnected: *btcutil.Block
// - NTBlockAccepted: *btcutil.Block
// - NTBlockConnected: *btcutil.Block
// - NTBlockDisconnected: *btcutil.Block
type Notification struct {
Type NotificationType
Data interface{}

View file

@ -1,51 +0,0 @@
// Copyright (c) 2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain
import (
"testing"
"github.com/btcsuite/btcd/chaincfg"
)
// TestNotifications ensures that notification callbacks are fired on events.
func TestNotifications(t *testing.T) {
blocks, err := loadBlocks("blk_0_to_4.dat.bz2")
if err != nil {
t.Fatalf("Error loading file: %v\n", err)
}
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("notifications",
&chaincfg.MainNetParams)
if err != nil {
t.Fatalf("Failed to setup chain instance: %v", err)
}
defer teardownFunc()
notificationCount := 0
callback := func(notification *Notification) {
if notification.Type == NTBlockAccepted {
notificationCount++
}
}
// Register callback multiple times then assert it is called that many
// times.
const numSubscribers = 3
for i := 0; i < numSubscribers; i++ {
chain.Subscribe(callback)
}
_, _, err = chain.ProcessBlock(blocks[1], BFNone)
if err != nil {
t.Fatalf("ProcessBlock fail on block 1: %v\n", err)
}
if notificationCount != numSubscribers {
t.Fatalf("Expected notification callback to be executed %d "+
"times, found %d", numSubscribers, notificationCount)
}
}

View file

@ -8,9 +8,9 @@ import (
"fmt"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
btcutil "github.com/lbryio/lbcutil"
)
// BehaviorFlags is a bitmask defining tweaks to the normal behavior when
@ -29,6 +29,10 @@ const (
// not be performed.
BFNoPoWCheck
// BFNoDupBlockCheck signals if the block should skip existence
// checks.
BFNoDupBlockCheck
// BFNone is a convenience value to specifically indicate no flags.
BFNone BehaviorFlags = 0
)
@ -148,24 +152,26 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bo
blockHash := block.Hash()
log.Tracef("Processing block %v", blockHash)
// The block must not already exist in the main chain or side chains.
exists, err := b.blockExists(blockHash)
if err != nil {
return false, false, err
}
if exists {
str := fmt.Sprintf("already have block %v", blockHash)
return false, false, ruleError(ErrDuplicateBlock, str)
}
if flags&BFNoDupBlockCheck != BFNoDupBlockCheck {
// The block must not already exist in the main chain or side chains.
exists, err := b.blockExists(blockHash)
if err != nil {
return false, false, err
}
if exists {
str := fmt.Sprintf("already have block %v", blockHash)
return false, false, ruleError(ErrDuplicateBlock, str)
}
// The block must not already exist as an orphan.
if _, exists := b.orphans[*blockHash]; exists {
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
return false, false, ruleError(ErrDuplicateBlock, str)
// The block must not already exist as an orphan.
if _, exists := b.orphans[*blockHash]; exists {
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
return false, false, ruleError(ErrDuplicateBlock, str)
}
}
// Perform preliminary sanity checks on the block and its transactions.
err = checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
err := checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
if err != nil {
return false, false, err
}

View file

@ -10,9 +10,9 @@ import (
"runtime"
"time"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
// txValidateItem holds a transaction along with which input to validate.

View file

@ -8,7 +8,7 @@ import (
"fmt"
"testing"
"github.com/btcsuite/btcd/txscript"
"github.com/lbryio/lbcd/txscript"
)
// TestCheckBlockScripts ensures that validating the all of the scripts in a

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,180 +0,0 @@
File path: reorgTest/blk_0_to_4.dat
Block 0:
f9beb4d9
1d010000
01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 3ba3edfd 7a7b12b2 7ac72c3e 67768f61 7fc81bc3 888a5132 3a9fb8aa
4b1e5e4a 29ab5f49 ffff001d 1dac2b7c
01
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff4d04ff ff001d01 04455468 65205469 6d657320 30332f4a
616e2f32 30303920 4368616e 63656c6c 6f72206f 6e206272 696e6b20 6f662073
65636f6e 64206261 696c6f75 7420666f 72206261 6e6b73ff ffffff01 00f2052a
01000000 43410467 8afdb0fe 55482719 67f1a671 30b7105c d6a828e0 3909a679
62e0ea1f 61deb649 f6bc3f4c ef38c4f3 5504e51e c112de5c 384df7ba 0b8d578a
4c702b6b f11d5fac 00000000
Block 1:
f9beb4d9
d4000000
01000000 6fe28c0a b6f1b372 c1a6a246 ae63f74f 931e8365 e15a089c 68d61900
00000000 3bbd67ad e98fbbb7 0718cd80 f9e9acf9 3b5fae91 7bb2b41d 4c3bb82c
77725ca5 81ad5f49 ffff001d 44e69904
01
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff04722f 2e2bffff ffff0100 f2052a01 00000043 41046868
0737c76d abb801cb 2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02
b5ac9e8b 4c9f49be 5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ac00
000000
Block 2:
f9beb4d9
95010000
01000000 13ca7940 4c11c63e ca906bbd f190b751 2872b857 1b5143ae e8cb5737
00000000 fc07c983 d7391736 0aeda657 29d0d4d3 2533eb84 76ee9d64 aa27538f
9b4fc00a d9af5f49 ffff001d 630bea22
02
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff04eb96 14e5ffff ffff0100 f2052a01 00000043 41046868
0737c76d abb801cb 2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02
b5ac9e8b 4c9f49be 5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ac00
000000
01000000 0163451d 1002611c 1388d5ba 4ddfdf99 196a86b5 990fb5b0 dc786207
4fdcb8ee d2000000 004a4930 46022100 3dde52c6 5e339f45 7fe1015e 70eed208
872eb71e dd484c07 206b190e cb2ec3f8 02210011 c78dcfd0 3d43fa63 61242a33
6291ba2a 8c1ef5bc d5472126 2468f2bf 8dee4d01 ffffffff 0200ca9a 3b000000
001976a9 14cb2abd e8bccacc 32e893df 3a054b9e f7f227a4 ce88ac00 286bee00
00000019 76a914ee 26c56fc1 d942be8d 7a24b2a1 001dd894 69398088 ac000000
00
Block 3:
f9beb4d9
96020000
01000000 7d338254 0506faab 0d4cf179 45dda023 49db51f9 6233f24c 28002258
00000000 4806fe80 bf85931b 882ea645 77ca5a03 22bb8af2 3f277b20 55f160cd
972c8e8b 31b25f49 ffff001d e8f0c653
03
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff044abd 8159ffff ffff0100 f2052a01 00000043 4104b95c
249d84f4 17e3e395 a1274254 28b54067 1cc15881 eb828c17 b722a53f c599e21c
a5e56c90 f340988d 3933acc7 6beb832f d64cab07 8ddf3ce7 32923031 d1a8ac00
000000
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
bad253d3 77010000 008c4930 46022100 96ee0d02 b35fd61e 4960b44f f396f67e
01fe17f9 de4e0c17 b6a963bd ab2b50a6 02210034 920d4daa 7e9f8abe 5675c931
495809f9 0b9c1189 d05fbaf1 dd6696a5 b0d8f301 41046868 0737c76d abb801cb
2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02 b5ac9e8b 4c9f49be
5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ffff ffff0100 286bee00
00000019 76a914c5 22664fb0 e55cdc5c 0cea73b4 aad97ec8 34323288 ac000000
00
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
bad253d3 77000000 008c4930 46022100 b08b922a c4bde411 1c229f92 9fe6eb6a
50161f98 1f4cf47e a9214d35 bf74d380 022100d2 f6640327 e677a1e1 cc474991
b9a48ba5 bd1e0c94 d1c8df49 f7b0193b 7ea4fa01 4104b95c 249d84f4 17e3e395
a1274254 28b54067 1cc15881 eb828c17 b722a53f c599e21c a5e56c90 f340988d
3933acc7 6beb832f d64cab07 8ddf3ce7 32923031 d1a8ffff ffff0100 ca9a3b00
00000019 76a914c5 22664fb0 e55cdc5c 0cea73b4 aad97ec8 34323288 ac000000
00
Block 4:
f9beb4d9
73010000
01000000 5da36499 06f35e09 9be42a1d 87b6dd42 11bc1400 6c220694 0807eaae
00000000 48eeeaed 2d9d8522 e6201173 743823fd 4b87cd8a ca8e6408 ec75ca38
302c2ff0 89b45f49 ffff001d 00530839
02
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff04d41d 2213ffff ffff0100 f2052a01 00000043 4104678a
fdb0fe55 48271967 f1a67130 b7105cd6 a828e039 09a67962 e0ea1f61 deb649f6
bc3f4cef 38c4f355 04e51ec1 12de5c38 4df7ba0b 8d578a4c 702b6bf1 1d5fac00
000000
01000000 0163451d 1002611c 1388d5ba 4ddfdf99 196a86b5 990fb5b0 dc786207
4fdcb8ee d2000000 004a4930 46022100 8c8fd57b 48762135 8d8f3e69 19f33e08
804736ff 83db47aa 248512e2 6df9b8ba 022100b0 c59e5ee7 bfcbfcd1 a4d83da9
55fb260e fda7f42a 25522625 a3d6f2d9 1174a701 ffffffff 0100f205 2a010000
001976a9 14c52266 4fb0e55c dc5c0cea 73b4aad9 7ec83432 3288ac00 000000
File path: reorgTest/blk_3A.dat
Block 3A:
f9beb4d9
96020000
01000000 7d338254 0506faab 0d4cf179 45dda023 49db51f9 6233f24c 28002258
00000000 5a15f573 1177a353 bdca7aab 20e16624 dfe90adc 70accadc 68016732
302c20a7 31b25f49 ffff001d 6a901440
03
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff04ad1b e7d5ffff ffff0100 f2052a01 00000043 4104ed83
704c95d8 29046f1a c2780621 1132102c 34e9ac7f fa1b7111 0658e5b9 d1bdedc4
16f5cefc 1db0625c d0c75de8 192d2b59 2d7e3b00 bcfb4a0e 860d880f d1fcac00
000000
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
bad253d3 77010000 008c4930 46022100 96ee0d02 b35fd61e 4960b44f f396f67e
01fe17f9 de4e0c17 b6a963bd ab2b50a6 02210034 920d4daa 7e9f8abe 5675c931
495809f9 0b9c1189 d05fbaf1 dd6696a5 b0d8f301 41046868 0737c76d abb801cb
2204f57d be4e4579 e4f710cd 67dc1b42 27592c81 e9b5cf02 b5ac9e8b 4c9f49be
5251056b 6a6d011e 4c37f6b6 d17ede6b 55faa235 19e2ffff ffff0100 286bee00
00000019 76a914c5 22664fb0 e55cdc5c 0cea73b4 aad97ec8 34323288 ac000000
00
01000000 01f287b5 e067e1cf 80f7da8a f89917b5 505094db d82412d9 35b665eb
bad253d3 77000000 008c4930 46022100 9cc67ddd aa6f592a 6b2babd4 d6ff954f
25a784cf 4fe4bb13 afb9f49b 08955119 022100a2 d99545b7 94080757 fcf2b563
f2e91287 86332f46 0ec6b90f f085fb28 41a69701 4104b95c 249d84f4 17e3e395
a1274254 28b54067 1cc15881 eb828c17 b722a53f c599e21c a5e56c90 f340988d
3933acc7 6beb832f d64cab07 8ddf3ce7 32923031 d1a8ffff ffff0100 ca9a3b00
00000019 76a914ee 26c56fc1 d942be8d 7a24b2a1 001dd894 69398088 ac000000
00
File path: reorgTest/blk_4A.dat
Block 4A:
f9beb4d9
d4000000
01000000 aae77468 2205667d 4f413a58 47cc8fe8 9795f1d5 645d5b24 1daf3c92
00000000 361c9cde a09637a0 d0c05c3b 4e7a5d91 9edb184a 0a4c7633 d92e2ddd
f04cb854 89b45f49 ffff001d 9e9aa1e8
01
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff0401b8 f3eaffff ffff0100 f2052a01 00000043 4104678a
fdb0fe55 48271967 f1a67130 b7105cd6 a828e039 09a67962 e0ea1f61 deb649f6
bc3f4cef 38c4f355 04e51ec1 12de5c38 4df7ba0b 8d578a4c 702b6bf1 1d5fac00
000000
File path: reorgTest/blk_5A.dat
Block 5A:
f9beb4d9
73010000
01000000 ebc7d0de 9c31a71b 7f41d275 2c080ba4 11e1854b d45cb2cf 8c1e4624
00000000 a607774b 79b8eb50 b52a5a32 c1754281 ec67f626 9561df28 57d1fe6a
ea82c696 e1b65f49 ffff001d 4a263577
02
01000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00ffffff ff049971 0c7dffff ffff0100 f2052a01 00000043 4104678a
fdb0fe55 48271967 f1a67130 b7105cd6 a828e039 09a67962 e0ea1f61 deb649f6
bc3f4cef 38c4f355 04e51ec1 12de5c38 4df7ba0b 8d578a4c 702b6bf1 1d5fac00
000000
01000000 0163451d 1002611c 1388d5ba 4ddfdf99 196a86b5 990fb5b0 dc786207
4fdcb8ee d2000000 004a4930 46022100 8c8fd57b 48762135 8d8f3e69 19f33e08
804736ff 83db47aa 248512e2 6df9b8ba 022100b0 c59e5ee7 bfcbfcd1 a4d83da9
55fb260e fda7f42a 25522625 a3d6f2d9 1174a701 ffffffff 0100f205 2a010000
001976a9 14c52266 4fb0e55c dc5c0cea 73b4aad9 7ec83432 3288ac00 000000

View file

@ -7,7 +7,7 @@ package blockchain
import (
"fmt"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/chaincfg/chainhash"
)
// ThresholdState define the various threshold states used when voting on
@ -302,6 +302,12 @@ func (b *BlockChain) deploymentState(prevNode *blockNode, deploymentID uint32) (
}
deployment := &b.chainParams.Deployments[deploymentID]
// added to mimic LBRYcrd:
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
return ThresholdActive, nil
}
checker := deploymentChecker{deployment: deployment, chain: b}
cache := &b.deploymentCaches[deploymentID]

View file

@ -7,7 +7,7 @@ package blockchain
import (
"testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/chaincfg/chainhash"
)
// TestThresholdStateStringer tests the stringized output for the

View file

@ -11,9 +11,9 @@ import (
"fmt"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/wire"
)
const (
@ -232,24 +232,25 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t
//
// The legacy format is as follows:
//
// <version><height><header code><unspentness bitmap>[<compressed txouts>,...]
// <version><height><header code><unspentness bitmap>[<compressed txouts>,...]
//
// Field Type Size
// version VLQ variable
// block height VLQ variable
// header code VLQ variable
// unspentness bitmap []byte variable
// compressed txouts
// compressed amount VLQ variable
// compressed script []byte variable
// Field Type Size
// version VLQ variable
// block height VLQ variable
// header code VLQ variable
// unspentness bitmap []byte variable
// compressed txouts
// compressed amount VLQ variable
// compressed script []byte variable
//
// The serialized header code format is:
// bit 0 - containing transaction is a coinbase
// bit 1 - output zero is unspent
// bit 2 - output one is unspent
// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2
// are unset, it encodes N-1 since there must be at least one unspent
// output.
//
// bit 0 - containing transaction is a coinbase
// bit 1 - output zero is unspent
// bit 2 - output one is unspent
// bits 3-x - number of bytes in unspentness bitmap. When both bits 1 and 2
// are unset, it encodes N-1 since there must be at least one unspent
// output.
//
// The rationale for the header code scheme is as follows:
// - Transactions which only pay to a single output and a change output are
@ -269,65 +270,65 @@ func determineMainChainBlocks(blocksMap map[chainhash.Hash]*blockChainContext, t
// From tx in main blockchain:
// Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098
//
// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52
// <><><><------------------------------------------------------------------>
// | | \--------\ |
// | height | compressed txout 0
// version header code
// 010103320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52
// <><><><------------------------------------------------------------------>
// | | \--------\ |
// | height | compressed txout 0
// version header code
//
// - version: 1
// - height: 1
// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness)
// - unspentness: Nothing since it is zero bytes
// - compressed txout 0:
// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC)
// - 0x04: special script type pay-to-pubkey
// - 0x96...52: x-coordinate of the pubkey
// - version: 1
// - height: 1
// - header code: 0x03 (coinbase, output zero unspent, 0 bytes of unspentness)
// - unspentness: Nothing since it is zero bytes
// - compressed txout 0:
// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC)
// - 0x04: special script type pay-to-pubkey
// - 0x96...52: x-coordinate of the pubkey
//
// Example 2:
// From tx in main blockchain:
// Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f
//
// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58
// <><----><><><------------------------------------------><-------------------------------------------->
// | | | \-------------------\ | |
// version | \--------\ unspentness | compressed txout 2
// height header code compressed txout 0
// 0185f90b0a011200e2ccd6ec7c6e2e581349c77e067385fa8236bf8a800900b8025be1b3efc63b0ad48e7f9f10e87544528d58
// <><----><><><------------------------------------------><-------------------------------------------->
// | | | \-------------------\ | |
// version | \--------\ unspentness | compressed txout 2
// height header code compressed txout 0
//
// - version: 1
// - height: 113931
// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap)
// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent)
// NOTE: It's +2 since the first two outputs are encoded in the header code
// - compressed txout 0:
// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC)
// - 0x00: special script type pay-to-pubkey-hash
// - 0xe2...8a: pubkey hash
// - compressed txout 2:
// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC)
// - 0x00: special script type pay-to-pubkey-hash
// - 0xb8...58: pubkey hash
// - version: 1
// - height: 113931
// - header code: 0x0a (output zero unspent, 1 byte in unspentness bitmap)
// - unspentness: [0x01] (bit 0 is set, so output 0+2 = 2 is unspent)
// NOTE: It's +2 since the first two outputs are encoded in the header code
// - compressed txout 0:
// - 0x12: VLQ-encoded compressed amount for 20000000 (0.2 BTC)
// - 0x00: special script type pay-to-pubkey-hash
// - 0xe2...8a: pubkey hash
// - compressed txout 2:
// - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC)
// - 0x00: special script type pay-to-pubkey-hash
// - 0xb8...58: pubkey hash
//
// Example 3:
// From tx in main blockchain:
// Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620
//
// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6
// <><----><><----><-------------------------------------------------->
// | | | \-----------------\ |
// version | \--------\ unspentness |
// height header code compressed txout 22
// 0193d06c100000108ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6
// <><----><><----><-------------------------------------------------->
// | | | \-----------------\ |
// version | \--------\ unspentness |
// height header code compressed txout 22
//
// - version: 1
// - height: 338156
// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap)
// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded.
// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent)
// NOTE: It's +2 since the first two outputs are encoded in the header code
// - compressed txout 22:
// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC)
// - 0x01: special script type pay-to-script-hash
// - 0x1d...e6: script hash
// - version: 1
// - height: 338156
// - header code: 0x10 (2+1 = 3 bytes in unspentness bitmap)
// NOTE: It's +1 since neither bit 1 nor 2 are set, so N-1 is encoded.
// - unspentness: [0x00 0x00 0x10] (bit 20 is set, so output 20+2 = 22 is unspent)
// NOTE: It's +2 since the first two outputs are encoded in the header code
// - compressed txout 22:
// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC)
// - 0x01: special script type pay-to-script-hash
// - 0x1d...e6: script hash
func deserializeUtxoEntryV0(serialized []byte) (map[uint32]*UtxoEntry, error) {
// Deserialize the version.
//

View file

@ -7,11 +7,11 @@ package blockchain
import (
"fmt"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/database"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
// txoFlags is a bitmask defining additional information and state for a

View file

@ -11,11 +11,11 @@ import (
"math/big"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
const (
@ -40,7 +40,7 @@ const (
// baseSubsidy is the starting subsidy amount for mined blocks. This
// value is halved every SubsidyHalvingInterval blocks.
baseSubsidy = 50 * btcutil.SatoshiPerBitcoin
baseSubsidy = 500 * btcutil.SatoshiPerBitcoin
)
var (
@ -192,17 +192,44 @@ func isBIP0030Node(node *blockNode) bool {
// At the target block generation rate for the main network, this is
// approximately every 4 years.
func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 {
if chainParams.SubsidyReductionInterval == 0 {
return baseSubsidy
h := int64(height)
if h == 0 {
return btcutil.SatoshiPerBitcoin * 4e8
}
if h <= 5100 {
return btcutil.SatoshiPerBitcoin
}
if h <= 55000 {
return btcutil.SatoshiPerBitcoin * (1 + (h-5001)/100)
}
// Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval)
return baseSubsidy >> uint(height/chainParams.SubsidyReductionInterval)
lv := (h - 55001) / int64(chainParams.SubsidyReductionInterval)
reduction := (int64(math.Sqrt((float64(8*lv))+1)) - 1) / 2
for !withinLevelBounds(reduction, lv) {
if ((reduction*reduction + reduction) >> 1) > lv {
reduction--
} else {
reduction++
}
}
subsidyReduction := btcutil.SatoshiPerBitcoin * reduction
if subsidyReduction >= baseSubsidy {
return 0
}
return baseSubsidy - subsidyReduction
}
func withinLevelBounds(reduction int64, lv int64) bool {
if ((reduction*reduction + reduction) >> 1) > lv {
return false
}
reduction++
return ((reduction*reduction + reduction) >> 1) > lv
}
// CheckTransactionSanity performs some preliminary checks on a transaction to
// ensure it is sane. These checks are context free.
func CheckTransactionSanity(tx *btcutil.Tx) error {
// ensure it is sane.
func CheckTransactionSanity(tx *btcutil.Tx, enforceSoftFork bool) error {
// A transaction must have at least one input.
msgTx := tx.MsgTx()
if len(msgTx.TxIn) == 0 {
@ -261,6 +288,11 @@ func CheckTransactionSanity(tx *btcutil.Tx) error {
btcutil.MaxSatoshi)
return ruleError(ErrBadTxOutValue, str)
}
err := txscript.AllClaimsAreSane(txOut.PkScript, enforceSoftFork)
if err != nil {
return ruleError(ErrBadTxOutValue, err.Error())
}
}
// Check for duplicate transaction inputs.
@ -302,8 +334,8 @@ func CheckTransactionSanity(tx *btcutil.Tx) error {
// target difficulty as claimed.
//
// The flags modify the behavior of this function as follows:
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
// difficulty is not performed.
// - BFNoPoWCheck: The check to ensure the block hash is less than the target
// difficulty is not performed.
func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags BehaviorFlags) error {
// The target difficulty must be larger than zero.
target := CompactToBig(header.Bits)
@ -324,7 +356,7 @@ func checkProofOfWork(header *wire.BlockHeader, powLimit *big.Int, flags Behavio
// to avoid proof of work checks is set.
if flags&BFNoPoWCheck != BFNoPoWCheck {
// The block hash must be less than the claimed target.
hash := header.BlockHash()
hash := header.BlockPoWHash()
hashNum := HashToBig(&hash)
if hashNum.Cmp(target) > 0 {
str := fmt.Sprintf("block hash of %064x is higher than "+
@ -515,7 +547,7 @@ func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource Median
// Do some preliminary checks on each transaction to ensure they are
// sane before continuing.
for _, tx := range transactions {
err := CheckTransactionSanity(tx)
err := CheckTransactionSanity(tx, false)
if err != nil {
return err
}
@ -637,8 +669,8 @@ func checkSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int32) error {
// which depend on its position within the block chain.
//
// The flags modify the behavior of this function as follows:
// - BFFastAdd: All checks except those involving comparing the header against
// the checkpoints are not performed.
// - BFFastAdd: All checks except those involving comparing the header against
// the checkpoints are not performed.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) checkBlockHeaderContext(header *wire.BlockHeader, prevNode *blockNode, flags BehaviorFlags) error {
@ -716,8 +748,8 @@ func (b *BlockChain) checkBlockHeaderContext(header *wire.BlockHeader, prevNode
// on its position within the block chain.
//
// The flags modify the behavior of this function as follows:
// - BFFastAdd: The transaction are not checked to see if they are finalized
// and the somewhat expensive BIP0034 validation is not performed.
// - BFFastAdd: The transaction are not checked to see if they are finalized
// and the somewhat expensive BIP0034 validation is not performed.
//
// The flags are also passed to checkBlockHeaderContext. See its documentation
// for how the flags modify its behavior.

View file

@ -5,15 +5,16 @@
package blockchain
import (
"encoding/hex"
"math"
"reflect"
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
// TestSequenceLocksActive tests the SequenceLockActive function to ensure it
@ -63,96 +64,11 @@ func TestSequenceLocksActive(t *testing.T) {
}
}
// TestCheckConnectBlockTemplate tests the CheckConnectBlockTemplate function to
// ensure it fails.
func TestCheckConnectBlockTemplate(t *testing.T) {
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("checkconnectblocktemplate",
&chaincfg.MainNetParams)
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return
}
defer teardownFunc()
// Since we're not dealing with the real block chain, set the coinbase
// maturity to 1.
chain.TstSetCoinbaseMaturity(1)
// Load up blocks such that there is a side chain.
// (genesis block) -> 1 -> 2 -> 3 -> 4
// \-> 3a
testFiles := []string{
"blk_0_to_4.dat.bz2",
"blk_3A.dat.bz2",
}
var blocks []*btcutil.Block
for _, file := range testFiles {
blockTmp, err := loadBlocks(file)
if err != nil {
t.Fatalf("Error loading file: %v\n", err)
}
blocks = append(blocks, blockTmp...)
}
for i := 1; i <= 3; i++ {
isMainChain, _, err := chain.ProcessBlock(blocks[i], BFNone)
if err != nil {
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error "+
"processing block %d: %v", i, err)
}
if !isMainChain {
t.Fatalf("CheckConnectBlockTemplate: Expected block %d to connect "+
"to main chain", i)
}
}
// Block 3 should fail to connect since it's already inserted.
err = chain.CheckConnectBlockTemplate(blocks[3])
if err == nil {
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
"on block 3")
}
// Block 4 should connect successfully to tip of chain.
err = chain.CheckConnectBlockTemplate(blocks[4])
if err != nil {
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
"block 4: %v", err)
}
// Block 3a should fail to connect since does not build on chain tip.
err = chain.CheckConnectBlockTemplate(blocks[5])
if err == nil {
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
"on block 3a")
}
// Block 4 should connect even if proof of work is invalid.
invalidPowBlock := *blocks[4].MsgBlock()
invalidPowBlock.Header.Nonce++
err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidPowBlock))
if err != nil {
t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
"block 4 with bad nonce: %v", err)
}
// Invalid block building on chain tip should fail to connect.
invalidBlock := *blocks[4].MsgBlock()
invalidBlock.Header.Bits--
err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidBlock))
if err == nil {
t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
"on block 4 with invalid difficulty bits")
}
}
// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works
// as expected.
func TestCheckBlockSanity(t *testing.T) {
powLimit := chaincfg.MainNetParams.PowLimit
block := btcutil.NewBlock(&Block100000)
block := GetBlock100000()
timeSource := NewMedianTime()
err := CheckBlockSanity(block, powLimit, timeSource)
if err != nil {
@ -234,254 +150,12 @@ func TestCheckSerializedHeight(t *testing.T) {
}
}
// Block100000 defines block 100,000 of the block chain. It is used to
var block100000Hex = "0000002024cbdc8644ee3983e66b003a0733891c069ca74c114c034c7b3e2e7ad7a12cd67e95e0555c0e056f6f2af538268ff9d21b420e529750d08eacb25c40f1322936637109b8a051157604c1c163cd39237687f6244b4e6d2b3a94e9d816babaecbb10c56058c811041b2b9c43000701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2003a086010410c56058081011314abf0100000d2f6e6f64655374726174756d2f000000000180354a6e0a0000001976a914b5e74e7cc9e1f480a6599895c92aab1401f870f188ac000000000100000002f1b75decc2c1c59c2178852822de412f574ad9796b65ac9092a79630d8109aaf000000006a47304402202f78ed3bf8dcadb6c17e289cd06e9c96b02c6f23aa1f446a4a7896a31cfd1e4702202862261e2eb59475ac91092c620b3cac5a831372bafc446d5ee450866040b532012103db4f3785354d84311fab7624c52784a61e3046d8f364463d327bdd96281b5b90feffffff987ee6b4bf95548d01e443683261dd0ffdcb2eb335b2f7119df0d41b60756b92010000006a47304402200c422c7560b6418d45443138bb957ec44eb293a639f4b2235a622205ca6cac370220759f15d5dc2543fd1aef80104c93427fcb025847bf895669025d1d82c62fbf6801210201864b998db5436990a0029fc3fb153c09e8c2689214b91c8ed68784995c8da0feffffff022bccfedd000000001976a914738f16132942a01d00cb9699bd058c4925aada3288ac1f4d030c000000001976a914c4292e757f5ff6a27c2f0a87d3a4aea5e46c275a88ac9f86010001000000015fbb26ad6d818186032baeef4d3f475dfe165c6da2d93411b8ec5f9f523cf1a4000000006a4730440220356999ad5a9f6f09b676f17dd4a2617a0af234722d68a50edc3768c983c0623d022056b4e5531608aeb0205fde9c44f741158da3bba1f4c3788c9fe79d36d43ea355012103509893a2a7c765d49ac9ff70126cb1af54871d70baba2c7e39ec9b4096289a9bfeffffff02389332fa080000001976a914f85e054405fbcedc2341cf8bf41ea989090587a288acf9321a41000000001976a914e85e90c048fdfbe1c2117a7132856ff4b39b470188ac9f86010001000000013508189b9bb61ac2aa536b905447b58f6c58c17cdef305240f566caa689d760a010000006a4730440220669a2b86e5abe58bae54829d3c271669540a9ad965c2fb79e8cc1fb609c0b60002202f958403d979138075cb53d8cb5ff6bb14e18d66dfdb6701c7d43a8ceeed0fa80121029935a602205a3fb72446064f3bc3a55ab9cd2e3459bf2ffdf80a48ab029d4b42feffffff02523c2f13000000001976a914c5b2ae398496f0f9ceaf81b83c28a27ddc890e3588ac211958f2000000001976a914ac65f1d16e5a2af37408b5d65406000a7ea143ca88ac9f8601000100000001bdd724322c555a21d5eb62d4aadbdc051663bcd4ec03f8d9005992f299783c21000000006a47304402205448141a2a788f73310025123bd24f5bee01dd8f48f18d7abc62d7c26465008902207ab46e6ddf6ba416decf3fbb97b6946a1428ea0a7c25a55cab47c47110d8e9ce0121029d6ff3b1235f2a08560b23dd4a08b14cc415b544801b885365736ea8ab1d3470feffffff029d104ccf000000001976a914999d5b0e3d5efcf601c711127b91841afbf5c37a88ace5c5a07f070000001976a9144aade372298eb387da9b6ac69d215a213e822f3f88ac9f86010001000000011658304d4ce796cd450228a10fdf647c6ea42295c9f5e1663df11481af1c884d010000006b483045022100a35d5d3ccde85b41559047d976ae6210b8e6ba5653c53aae1adc90048de0761002200d6bd6ebc6d73f97855f435c6fd595009ee71d23bb34870ab83ad53f67eeb22b012102d2f681ebfd1a570416d602986a47ca4254d8dedf2935b3f8c2ba55dcee8e98f4feffffff025ee913e6020000001976a91468076c9380d3c6b468ad1d6109c36770fb181e8f88acb165394f000000001976a9147ae970e81b3657cbb59df26517e372165807be0088ac9f86010001000000018f285109f78524a88ff328a4f94de2ac03224c50984b11c68adda192e8f78efa010000006b483045022100d77f2ac32dd6a3015f02f7115a13f617c57952fc5d53a33a87dc3fc00ffe1864022006455f74cff864b10424e445c530a59243f86d309dc92c5010ec5709e38471ab012102fdac7335b41edcd2846fc7e2166bb48312ee583ed6ff70fb5c27bcb2addaad86feffffff028b7a6d5c000000001976a914c65106d2e7ea4ec6aa8aa30ba4d11cfd1143123388ac5934c228000000001976a914d1c4d190b07edb972b91f33c36c6568b80358dd488ac9f860100"
// GetBlock100000 defines block 100,000 of the block chain. It is used to
// test Block operations.
var Block100000 = wire.MsgBlock{
Header: wire.BlockHeader{
Version: 1,
PrevBlock: chainhash.Hash([32]byte{ // Make go vet happy.
0x50, 0x12, 0x01, 0x19, 0x17, 0x2a, 0x61, 0x04,
0x21, 0xa6, 0xc3, 0x01, 0x1d, 0xd3, 0x30, 0xd9,
0xdf, 0x07, 0xb6, 0x36, 0x16, 0xc2, 0xcc, 0x1f,
0x1c, 0xd0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
}), // 000000000002d01c1fccc21636b607dfd930d31d01c3a62104612a1719011250
MerkleRoot: chainhash.Hash([32]byte{ // Make go vet happy.
0x66, 0x57, 0xa9, 0x25, 0x2a, 0xac, 0xd5, 0xc0,
0xb2, 0x94, 0x09, 0x96, 0xec, 0xff, 0x95, 0x22,
0x28, 0xc3, 0x06, 0x7c, 0xc3, 0x8d, 0x48, 0x85,
0xef, 0xb5, 0xa4, 0xac, 0x42, 0x47, 0xe9, 0xf3,
}), // f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766
Timestamp: time.Unix(1293623863, 0), // 2010-12-29 11:57:43 +0000 UTC
Bits: 0x1b04864c, // 453281356
Nonce: 0x10572b0f, // 274148111
},
Transactions: []*wire.MsgTx{
{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 0xffffffff,
},
SignatureScript: []byte{
0x04, 0x4c, 0x86, 0x04, 0x1b, 0x02, 0x06, 0x02,
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0x12a05f200, // 5000000000
PkScript: []byte{
0x41, // OP_DATA_65
0x04, 0x1b, 0x0e, 0x8c, 0x25, 0x67, 0xc1, 0x25,
0x36, 0xaa, 0x13, 0x35, 0x7b, 0x79, 0xa0, 0x73,
0xdc, 0x44, 0x44, 0xac, 0xb8, 0x3c, 0x4e, 0xc7,
0xa0, 0xe2, 0xf9, 0x9d, 0xd7, 0x45, 0x75, 0x16,
0xc5, 0x81, 0x72, 0x42, 0xda, 0x79, 0x69, 0x24,
0xca, 0x4e, 0x99, 0x94, 0x7d, 0x08, 0x7f, 0xed,
0xf9, 0xce, 0x46, 0x7c, 0xb9, 0xf7, 0xc6, 0x28,
0x70, 0x78, 0xf8, 0x01, 0xdf, 0x27, 0x6f, 0xdf,
0x84, // 65-byte signature
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash([32]byte{ // Make go vet happy.
0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60,
0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac,
0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07,
0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87,
}), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03
Index: 0,
},
SignatureScript: []byte{
0x49, // OP_DATA_73
0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3,
0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6,
0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94,
0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58,
0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00,
0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62,
0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c,
0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60,
0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48,
0x01, // 73-byte signature
0x41, // OP_DATA_65
0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d,
0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38,
0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25,
0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e,
0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8,
0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd,
0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b,
0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3,
0xd3, // 65-byte pubkey
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0x2123e300, // 556000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60,
0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e,
0xf7, 0xf5, 0x8b, 0x32,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
{
Value: 0x108e20f00, // 4444000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f,
0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b,
0x52, 0xde, 0x3d, 0x7c,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash([32]byte{ // Make go vet happy.
0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d,
0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27,
0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65,
0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf,
}), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3
Index: 1,
},
SignatureScript: []byte{
0x47, // OP_DATA_71
0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf,
0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5,
0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34,
0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31,
0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee,
0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f,
0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c,
0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e,
0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01,
0x41, // OP_DATA_65
0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78,
0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5,
0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39,
0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21,
0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee,
0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3,
0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95,
0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85,
0x0f, // 65-byte pubkey
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0xf4240, // 1000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04,
0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d,
0xad, 0xbe, 0x7e, 0x10,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
{
Value: 0x11d260c0, // 299000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1,
0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab,
0xb3, 0x40, 0x9c, 0xd9,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash([32]byte{ // Make go vet happy.
0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73,
0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac,
0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90,
0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4,
}), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b
Index: 0,
},
SignatureScript: []byte{
0x49, // OP_DATA_73
0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2,
0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c,
0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd,
0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f,
0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00,
0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14,
0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb,
0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c,
0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3,
0x01, // 73-byte signature
0x41, // OP_DATA_65
0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97,
0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18,
0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17,
0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94,
0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65,
0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f,
0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce,
0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f,
0xbb, // 65-byte pubkey
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0xf4240, // 1000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7,
0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b,
0xf2, 0xeb, 0x9e, 0xe0,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
},
func GetBlock100000() *btcutil.Block {
var block100000Bytes, _ = hex.DecodeString(block100000Hex)
var results, _ = btcutil.NewBlockFromBytes(block100000Bytes)
return results
}

View file

@ -7,7 +7,7 @@ package blockchain
import (
"math"
"github.com/btcsuite/btcd/chaincfg"
"github.com/lbryio/lbcd/chaincfg"
)
const (
@ -195,6 +195,12 @@ func (b *BlockChain) calcNextBlockVersion(prevNode *blockNode) (int32, error) {
expectedVersion := uint32(vbTopBits)
for id := 0; id < len(b.chainParams.Deployments); id++ {
deployment := &b.chainParams.Deployments[id]
// added to mimic LBRYcrd:
if deployment.ForceActiveAt > 0 && prevNode != nil && prevNode.height+1 >= deployment.ForceActiveAt {
continue
}
cache := &b.deploymentCaches[id]
checker := deploymentChecker{deployment: deployment, chain: b}
state, err := b.thresholdState(prevNode, checker, cache)

View file

@ -7,9 +7,9 @@ package blockchain
import (
"fmt"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/txscript"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
const (
@ -20,11 +20,11 @@ const (
// weight of a "base" byte is 4, while the weight of a witness byte is
// 1. As a result, for a block to be valid, the BlockWeight MUST be
// less than, or equal to MaxBlockWeight.
MaxBlockWeight = 4000000
MaxBlockWeight = 8000000
// MaxBlockBaseSize is the maximum number of bytes within a block
// which can be allocated to non-witness data.
MaxBlockBaseSize = 1000000
MaxBlockBaseSize = 8000000
// MaxBlockSigOpsCost is the maximum number of signature operations
// allowed for a block. It is calculated via a weighted algorithm which

View file

@ -1,68 +1,11 @@
btcec
=====
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://pkg.go.dev/github.com/btcsuite/btcd/btcec?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/btcec)
Package btcec implements elliptic curve cryptography needed for working with
btcec implements elliptic curve cryptography needed for working with
Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
standard crypto/ecdsa packages provided with go. A comprehensive suite of test
is provided to ensure proper functionality. Package btcec was originally based
on work from ThePiachu which is licensed under the same terms as Go, but it has
signficantly diverged since then. The btcsuite developers original is licensed
under the liberal ISC license.
Although this package was primarily written for btcd, it has intentionally been
designed so it can be used as a standalone package for any projects needing to
use secp256k1 elliptic curve cryptography.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/btcec
```
## Examples
* [Sign Message](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--SignMessage)
Demonstrates signing a message with a secp256k1 private key that is first
parsed form raw bytes and serializing the generated signature.
* [Verify Signature](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--VerifySignature)
Demonstrates verifying a secp256k1 signature against a public key that is
first parsed from raw bytes. The signature is also parsed from raw bytes.
* [Encryption](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--EncryptMessage)
Demonstrates encrypting a message for a public key that is first parsed from
raw bytes, then decrypting it using the corresponding private key.
* [Decryption](https://pkg.go.dev/github.com/btcsuite/btcd/btcec#example-package--DecryptMessage)
Demonstrates decrypting a message using a private key that is first parsed
from raw bytes.
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code
has not been tampered with and is coming from the btcsuite developers. To
verify the signature perform the following:
- Download the public key from the Conformal website at
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
- Import the public key into your GPG keyring:
```bash
gpg --import GIT-GPG-KEY-conformal.txt
```
- Verify the release tag with the following command where `TAG_NAME` is a
placeholder for the specific tag:
```bash
git tag -v TAG_NAME
```
## License
Package btcec is licensed under the [copyfree](http://copyfree.org) ISC License
except for btcec.go and btcec_test.go which is under the same license as Go.
signficantly diverged since then.

View file

@ -527,7 +527,7 @@ type baseMultTest struct {
x, y string
}
//TODO: add more test vectors
// TODO: add more test vectors
var s256BaseMultTests = []baseMultTest{
{
"AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522",
@ -556,7 +556,7 @@ var s256BaseMultTests = []baseMultTest{
},
}
//TODO: test different curves as well?
// TODO: test different curves as well?
func TestBaseMult(t *testing.T) {
s256 := S256()
for i, e := range s256BaseMultTests {

View file

@ -8,8 +8,8 @@ import (
"encoding/hex"
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/btcec"
"github.com/lbryio/lbcd/chaincfg/chainhash"
)
// This example demonstrates signing a message with a secp256k1 private key that

View file

@ -125,27 +125,30 @@ var (
// the arithmetic needed for elliptic curve operations.
//
// The following depicts the internal representation:
// -----------------------------------------------------------------
// | n[9] | n[8] | ... | n[0] |
// | 32 bits available | 32 bits available | ... | 32 bits available |
// | 22 bits for value | 26 bits for value | ... | 26 bits for value |
// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow |
// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) |
// -----------------------------------------------------------------
//
// -----------------------------------------------------------------
// | n[9] | n[8] | ... | n[0] |
// | 32 bits available | 32 bits available | ... | 32 bits available |
// | 22 bits for value | 26 bits for value | ... | 26 bits for value |
// | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow |
// | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) |
// -----------------------------------------------------------------
//
// For example, consider the number 2^49 + 1. It would be represented as:
// n[0] = 1
// n[1] = 2^23
// n[2..9] = 0
//
// n[0] = 1
// n[1] = 2^23
// n[2..9] = 0
//
// The full 256-bit value is then calculated by looping i from 9..0 and
// doing sum(n[i] * 2^(26i)) like so:
// n[9] * 2^(26*9) = 0 * 2^234 = 0
// n[8] * 2^(26*8) = 0 * 2^208 = 0
// ...
// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49
// n[0] * 2^(26*0) = 1 * 2^0 = 1
// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
//
// n[9] * 2^(26*9) = 0 * 2^234 = 0
// n[8] * 2^(26*8) = 0 * 2^208 = 0
// ...
// n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49
// n[0] * 2^(26*0) = 1 * 2^0 = 1
// Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1
type fieldVal struct {
n [10]uint32
}

View file

@ -5,6 +5,7 @@
// This file is ignored during the regular build due to the following build tag.
// It is called by go generate and used to automatically generate pre-computed
// tables used to accelerate operations.
//go:build ignore
// +build ignore
package main
@ -17,7 +18,7 @@ import (
"log"
"os"
"github.com/btcsuite/btcd/btcec"
"github.com/lbryio/lbcd/btcec"
)
func main() {

View file

@ -4,6 +4,7 @@
// This file is ignored during the regular build due to the following build tag.
// This build tag is set during go generate.
//go:build gensecp256k1
// +build gensecp256k1
package btcec

View file

@ -12,7 +12,7 @@ import (
"strings"
)
//go:generate go run -tags gensecp256k1 genprecomps.go
//go:rm -f gensecp256k1.go; generate go run -tags gensecp256k1 genprecomps.go
// loadS256BytePoints decompresses and deserializes the pre-computed byte points
// used to accelerate scalar base multiplication for the secp256k1 curve. This

View file

@ -353,6 +353,10 @@ func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
// step to prevent the jacobian conversion back and forth.
Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy)
if Qx.Sign() == 0 && Qy.Sign() == 0 {
return nil, errors.New("point (Qx, Qy) equals the point at infinity")
}
return &PublicKey{
Curve: curve,
X: Qx,

View file

@ -549,6 +549,12 @@ var recoveryTests = []struct {
sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
err: fmt.Errorf("invalid square root"),
},
{
// Point at infinity recovered
msg: "6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
sig: "0079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9",
err: fmt.Errorf("point (Qx, Qy) equals the point at infinity"),
},
{
// Low R and S values.
msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f",

View file

@ -1,70 +1,8 @@
btcjson
=======
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson)
Package btcjson implements concrete types for marshalling to and from the
bitcoin JSON-RPC API. A comprehensive suite of tests is provided to ensure
proper functionality.
Although this package was primarily written for the btcsuite, it has
intentionally been designed so it can be used as a standalone package for any
projects needing to marshal to and from bitcoin JSON-RPC requests and responses.
Note that although it's possible to use this package directly to implement an
RPC client, it is not recommended since it is only intended as an infrastructure
package. Instead, RPC clients should use the
[btcrpcclient](https://github.com/btcsuite/btcrpcclient) package which provides
a full blown RPC client with many features such as automatic connection
management, websocket support, automatic notification re-registration on
reconnect, and conversion from the raw underlying RPC types (strings, floats,
ints, etc) to higher-level types with many nice and useful properties.
## Installation and Updating
```bash
$ go get -u github.com/btcsuite/btcd/btcjson
```
## Examples
* [Marshal Command](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-MarshalCmd)
Demonstrates how to create and marshal a command into a JSON-RPC request.
* [Unmarshal Command](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-UnmarshalCmd)
Demonstrates how to unmarshal a JSON-RPC request and then unmarshal the
concrete request into a concrete command.
* [Marshal Response](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-MarshalResponse)
Demonstrates how to marshal a JSON-RPC response.
* [Unmarshal Response](https://pkg.go.dev/github.com/btcsuite/btcd/btcjson#example-package--UnmarshalResponse)
Demonstrates how to unmarshal a JSON-RPC response and then unmarshal the
result field in the response to a concrete type.
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code
has not been tampered with and is coming from the btcsuite developers. To
verify the signature perform the following:
- Download the public key from the Conformal website at
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
- Import the public key into your GPG keyring:
```bash
gpg --import GIT-GPG-KEY-conformal.txt
```
- Verify the release tag with the following command where `TAG_NAME` is a
placeholder for the specific tag:
```bash
git tag -v TAG_NAME
```
## License
Package btcjson is licensed under the [copyfree](http://copyfree.org) ISC
License.
proper functionality.

View file

@ -12,7 +12,7 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/btcjson"
)
// TestBtcdExtCmds tests all of the btcd extended commands marshal and unmarshal

View file

@ -9,7 +9,7 @@ import (
"encoding/json"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/btcjson"
)
// TestBtcdExtCustomResults ensures any results that have custom marshalling

View file

@ -11,7 +11,7 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/btcjson"
)
// TestBtcWalletExtCmds tests all of the btcwallet extended commands marshal and

View file

@ -13,7 +13,7 @@ import (
"fmt"
"reflect"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/wire"
)
// AddNodeSubCmd defines the type used in the addnode JSON-RPC command for the
@ -48,6 +48,15 @@ func NewAddNodeCmd(addr string, subCmd AddNodeSubCmd) *AddNodeCmd {
}
}
// ClearBannedCmd defines the clearbanned JSON-RPC command.
type ClearBannedCmd struct{}
// NewClearBannedCmd returns a new instance which can be used to issue an clearbanned
// JSON-RPC command.
func NewClearBannedCmd() *ClearBannedCmd {
return &ClearBannedCmd{}
}
// TransactionInput represents the inputs to a transaction. Specifically a
// transaction hash and output number pair.
type TransactionInput struct {
@ -58,7 +67,7 @@ type TransactionInput struct {
// CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command.
type CreateRawTransactionCmd struct {
Inputs []TransactionInput
Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC
Outputs map[string]interface{} `jsonrpcusage:"{\"address\":amount, \"data\":\"hex\", ...}"`
LockTime *int64
}
@ -67,7 +76,7 @@ type CreateRawTransactionCmd struct {
//
// Amounts are in BTC. Passing in nil and the empty slice as inputs is equivalent,
// both gets interpreted as the empty slice.
func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64,
func NewCreateRawTransactionCmd(inputs []TransactionInput, outputs map[string]interface{},
lockTime *int64) *CreateRawTransactionCmd {
// to make sure we're serializing this to the empty list and not null, we
// explicitly initialize the list
@ -76,7 +85,7 @@ func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]fl
}
return &CreateRawTransactionCmd{
Inputs: inputs,
Amounts: amounts,
Outputs: outputs,
LockTime: lockTime,
}
}
@ -650,7 +659,7 @@ func NewGetRawMempoolCmd(verbose *bool) *GetRawMempoolCmd {
// Core even though it really should be a bool.
type GetRawTransactionCmd struct {
Txid string
Verbose *int `jsonrpcdefault:"0"`
Verbose *bool `jsonrpcdefault:"false"`
}
// NewGetRawTransactionCmd returns a new instance which can be used to issue a
@ -658,7 +667,7 @@ type GetRawTransactionCmd struct {
//
// The parameters which are pointers indicate they are optional. Passing nil
// for optional parameters will use the default value.
func NewGetRawTransactionCmd(txHash string, verbose *int) *GetRawTransactionCmd {
func NewGetRawTransactionCmd(txHash string, verbose *bool) *GetRawTransactionCmd {
return &GetRawTransactionCmd{
Txid: txHash,
Verbose: verbose,
@ -757,6 +766,15 @@ func NewInvalidateBlockCmd(blockHash string) *InvalidateBlockCmd {
}
}
// ListBannedCmd defines the listbanned JSON-RPC command.
type ListBannedCmd struct{}
// NewListBannedCmd returns a new instance which can be used to issue a listbanned
// JSON-RPC command.
func NewListBannedCmd() *ListBannedCmd {
return &ListBannedCmd{}
}
// PingCmd defines the ping JSON-RPC command.
type PingCmd struct{}
@ -903,6 +921,39 @@ func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTr
}
}
// SetBanSubCmd defines the type used in the setban JSON-RPC command for the
// sub command field.
type SetBanSubCmd string
const (
// SBAdd indicates the specified host should be added as a persistent
// peer.
SBAdd SetBanSubCmd = "add"
// SBRemove indicates the specified peer should be removed.
SBRemove SetBanSubCmd = "remove"
)
// SetBanCmd defines the setban JSON-RPC command.
type SetBanCmd struct {
Addr string
SubCmd SetBanSubCmd `jsonrpcusage:"\"add|remove\""`
BanTime *int `jsonrpcdefault:"0"`
Absolute *bool `jsonrpcdefault:"false"`
}
// NewSetBanCmd returns a new instance which can be used to issue an setban
// JSON-RPC command.
func NewSetBanCmd(addr string, subCmd SetBanSubCmd, banTime *int,
absolute *bool) *SetBanCmd {
return &SetBanCmd{
Addr: addr,
SubCmd: subCmd,
BanTime: banTime,
Absolute: absolute,
}
}
// SetGenerateCmd defines the setgenerate JSON-RPC command.
type SetGenerateCmd struct {
Generate bool
@ -1080,6 +1131,9 @@ func init() {
MustRegisterCmd("getnetworkhashps", (*GetNetworkHashPSCmd)(nil), flags)
MustRegisterCmd("getnodeaddresses", (*GetNodeAddressesCmd)(nil), flags)
MustRegisterCmd("getpeerinfo", (*GetPeerInfoCmd)(nil), flags)
MustRegisterCmd("listbanned", (*ListBannedCmd)(nil), flags)
MustRegisterCmd("setban", (*SetBanCmd)(nil), flags)
MustRegisterCmd("clearbanned", (*ClearBannedCmd)(nil), flags)
MustRegisterCmd("getrawmempool", (*GetRawMempoolCmd)(nil), flags)
MustRegisterCmd("getrawtransaction", (*GetRawTransactionCmd)(nil), flags)
MustRegisterCmd("gettxout", (*GetTxOutCmd)(nil), flags)

View file

@ -12,8 +12,8 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/lbcd/btcjson"
"github.com/lbryio/lbcd/wire"
)
// TestChainSvrCmds tests all of the chain server commands marshal and unmarshal
@ -52,13 +52,13 @@ func TestChainSvrCmds(t *testing.T) {
txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1},
}
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil)
txOutputs := map[string]interface{}{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Amounts: map[string]float64{"456": .0123},
Outputs: map[string]interface{}{"456": .0123},
},
},
{
@ -67,13 +67,13 @@ func TestChainSvrCmds(t *testing.T) {
return btcjson.NewCmd("createrawtransaction", `[]`, `{"456":0.0123}`)
},
staticCmd: func() interface{} {
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(nil, amounts, nil)
txOutputs := map[string]interface{}{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(nil, txOutputs, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[],{"456":0.0123}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{},
Amounts: map[string]float64{"456": .0123},
Outputs: map[string]interface{}{"456": .0123},
},
},
{
@ -86,16 +86,35 @@ func TestChainSvrCmds(t *testing.T) {
txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1},
}
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333))
txOutputs := map[string]interface{}{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, btcjson.Int64(12312333333))
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Amounts: map[string]float64{"456": .0123},
Outputs: map[string]interface{}{"456": .0123},
LockTime: btcjson.Int64(12312333333),
},
},
{
name: "createrawtransaction with data",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
`{"data":"6a134920616d204672616374616c456e6372797074"}`)
},
staticCmd: func() interface{} {
txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1},
}
txOutputs := map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"}
return btcjson.NewCreateRawTransactionCmd(txInputs, txOutputs, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"data":"6a134920616d204672616374616c456e6372797074"}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Outputs: map[string]interface{}{"data": "6a134920616d204672616374616c456e6372797074"},
},
},
{
name: "fundrawtransaction - empty opts",
newCmd: func() (i interface{}, e error) {
@ -388,7 +407,7 @@ func TestChainSvrCmds(t *testing.T) {
return btcjson.NewGetBlockFilterCmd("0000afaf", nil)
},
marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf"],"id":1}`,
unmarshalled: &btcjson.GetBlockFilterCmd{"0000afaf", nil},
unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: nil},
},
{
name: "getblockfilter optional filtertype",
@ -399,7 +418,7 @@ func TestChainSvrCmds(t *testing.T) {
return btcjson.NewGetBlockFilterCmd("0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic))
},
marshalled: `{"jsonrpc":"1.0","method":"getblockfilter","params":["0000afaf","basic"],"id":1}`,
unmarshalled: &btcjson.GetBlockFilterCmd{"0000afaf", btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)},
unmarshalled: &btcjson.GetBlockFilterCmd{BlockHash: "0000afaf", FilterType: btcjson.NewFilterTypeName(btcjson.FilterTypeBasic)},
},
{
name: "getblockhash",
@ -872,21 +891,21 @@ func TestChainSvrCmds(t *testing.T) {
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123"],"id":1}`,
unmarshalled: &btcjson.GetRawTransactionCmd{
Txid: "123",
Verbose: btcjson.Int(0),
Verbose: btcjson.Bool(false),
},
},
{
name: "getrawtransaction optional",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getrawtransaction", "123", 1)
return btcjson.NewCmd("getrawtransaction", "123", true)
},
staticCmd: func() interface{} {
return btcjson.NewGetRawTransactionCmd("123", btcjson.Int(1))
return btcjson.NewGetRawTransactionCmd("123", btcjson.Bool(true))
},
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",1],"id":1}`,
marshalled: `{"jsonrpc":"1.0","method":"getrawtransaction","params":["123",true],"id":1}`,
unmarshalled: &btcjson.GetRawTransactionCmd{
Txid: "123",
Verbose: btcjson.Int(1),
Verbose: btcjson.Bool(true),
},
},
{

View file

@ -9,10 +9,10 @@ import (
"encoding/hex"
"encoding/json"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lbryio/lbcd/wire"
btcutil "github.com/lbryio/lbcutil"
)
// GetBlockHeaderVerboseResult models the data from the getblockheader command when
@ -25,6 +25,7 @@ type GetBlockHeaderVerboseResult struct {
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
ClaimTrie string `json:"nameclaimroot,omitempty"`
Time int64 `json:"time"`
Nonce uint64 `json:"nonce"`
Bits string `json:"bits"`
@ -34,35 +35,60 @@ type GetBlockHeaderVerboseResult struct {
}
// GetBlockStatsResult models the data from the getblockstats command.
// Pointers are used instead of values to allow for optional fields.
type GetBlockStatsResult struct {
AverageFee int64 `json:"avgfee"`
AverageFeeRate int64 `json:"avgfeerate"`
AverageTxSize int64 `json:"avgtxsize"`
FeeratePercentiles []int64 `json:"feerate_percentiles"`
Hash string `json:"blockhash"`
Height int64 `json:"height"`
Ins int64 `json:"ins"`
MaxFee int64 `json:"maxfee"`
MaxFeeRate int64 `json:"maxfeerate"`
MaxTxSize int64 `json:"maxtxsize"`
MedianFee int64 `json:"medianfee"`
MedianTime int64 `json:"mediantime"`
MedianTxSize int64 `json:"mediantxsize"`
MinFee int64 `json:"minfee"`
MinFeeRate int64 `json:"minfeerate"`
MinTxSize int64 `json:"mintxsize"`
Outs int64 `json:"outs"`
SegWitTotalSize int64 `json:"swtotal_size"`
SegWitTotalWeight int64 `json:"swtotal_weight"`
SegWitTxs int64 `json:"swtxs"`
Subsidy int64 `json:"subsidy"`
Time int64 `json:"time"`
TotalOut int64 `json:"total_out"`
TotalSize int64 `json:"total_size"`
TotalWeight int64 `json:"total_weight"`
Txs int64 `json:"txs"`
UTXOIncrease int64 `json:"utxo_increase"`
UTXOSizeIncrease int64 `json:"utxo_size_inc"`
AverageFee *int64 `json:"avgfee,omitempty"`
AverageFeeRate *int64 `json:"avgfeerate,omitempty"`
AverageTxSize *int64 `json:"avgtxsize,omitempty"`
FeeratePercentiles *[]int64 `json:"feerate_percentiles,omitempty"`
Hash *string `json:"blockhash,omitempty"`
Height *int64 `json:"height,omitempty"`
Ins *int64 `json:"ins,omitempty"`
MaxFee *int64 `json:"maxfee,omitempty"`
MaxFeeRate *int64 `json:"maxfeerate,omitempty"`
MaxTxSize *int64 `json:"maxtxsize,omitempty"`
MedianFee *int64 `json:"medianfee,omitempty"`
MedianTime *int64 `json:"mediantime,omitempty"`
MedianTxSize *int64 `json:"mediantxsize,omitempty"`
MinFee *int64 `json:"minfee,omitempty"`
MinFeeRate *int64 `json:"minfeerate,omitempty"`
MinTxSize *int64 `json:"mintxsize,omitempty"`
Outs *int64 `json:"outs,omitempty"`
SegWitTotalSize *int64 `json:"swtotal_size,omitempty"`
SegWitTotalWeight *int64 `json:"swtotal_weight,omitempty"`
SegWitTxs *int64 `json:"swtxs,omitempty"`
Subsidy *int64 `json:"subsidy,omitempty"`
Time *int64 `json:"time,omitempty"`
TotalOut *int64 `json:"total_out,omitempty"`
TotalSize *int64 `json:"total_size,omitempty"`
TotalWeight *int64 `json:"total_weight,omitempty"`
TotalFee *int64 `json:"totalfee,omitempty"`
Txs *int64 `json:"txs,omitempty"`
UTXOIncrease *int64 `json:"utxo_increase,omitempty"`
UTXOSizeIncrease *int64 `json:"utxo_size_inc,omitempty"`
}
type GetBlockVerboseResultBase struct {
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
StrippedSize int32 `json:"strippedsize"`
Size int32 `json:"size"`
Weight int32 `json:"weight"`
Height int64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Time int64 `json:"time"`
MedianTime int64 `json:"mediantime"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
ChainWork string `json:"chainwork"`
PreviousHash string `json:"previousblockhash,omitempty"`
NextHash string `json:"nextblockhash,omitempty"`
ClaimTrie string `json:"nameclaimroot,omitempty"`
TxCount int `json:"nTx"` // For backwards compatibility only
}
// GetBlockVerboseResult models the data from the getblock command when the
@ -72,23 +98,8 @@ type GetBlockStatsResult struct {
// getblock returns an object whose tx field is an array of raw transactions.
// Use GetBlockVerboseTxResult to unmarshal data received from passing verbose=2 to getblock.
type GetBlockVerboseResult struct {
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
StrippedSize int32 `json:"strippedsize"`
Size int32 `json:"size"`
Weight int32 `json:"weight"`
Height int64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Tx []string `json:"tx,omitempty"`
RawTx []TxRawResult `json:"rawtx,omitempty"` // Note: this field is always empty when verbose != 2.
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
GetBlockVerboseResultBase
Tx []string `json:"tx"`
}
// GetBlockVerboseTxResult models the data from the getblock command when the
@ -98,23 +109,8 @@ type GetBlockVerboseResult struct {
// getblock returns an object whose tx field is an array of raw transactions.
// Use GetBlockVerboseResult to unmarshal data received from passing verbose=1 to getblock.
type GetBlockVerboseTxResult struct {
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
StrippedSize int32 `json:"strippedsize"`
Size int32 `json:"size"`
Weight int32 `json:"weight"`
Height int64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Tx []TxRawResult `json:"tx,omitempty"`
RawTx []TxRawResult `json:"rawtx,omitempty"` // Deprecated: removed in Bitcoin Core
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
GetBlockVerboseResultBase
Tx []TxRawResult `json:"tx"`
}
// GetChainTxStatsResult models the data from the getchaintxstats command.
@ -296,6 +292,10 @@ type GetBlockTemplateResult struct {
// Block proposal from BIP 0023.
Capabilities []string `json:"capabilities,omitempty"`
RejectReasion string `json:"reject-reason,omitempty"`
ClaimTrieHash string `json:"claimtrie"`
Rules []string `json:"rules,omitempty"`
}
// GetMempoolEntryResult models the data returned from the getmempoolentry's
@ -327,13 +327,27 @@ type GetMempoolEntryResult struct {
WTxId string `json:"wtxid"`
Fees MempoolFees `json:"fees"`
Depends []string `json:"depends"`
SpentBy []string `json:"spentby"`
}
// GetChainTipsResult models the data returns from the getchaintips command.
type GetChainTipsResult struct {
Height int64 `json:"height"`
Hash string `json:"hash"`
BranchLen int64 `json:"branchlen"`
Status string `json:"status"`
}
// GetMempoolInfoResult models the data returned from the getmempoolinfo
// command.
type GetMempoolInfoResult struct {
Size int64 `json:"size"`
Bytes int64 `json:"bytes"`
Size int64 `json:"size"` // Current tx count
Bytes int64 `json:"bytes"` // Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted
Usage int64 `json:"usage"` // Total memory usage for the mempool
TotalFee float64 `json:"total_fee"` // Total fees for the mempool in LBC, ignoring modified fees through prioritizetransaction
MemPoolMinFee float64 `json:"mempoolminfee"` // Minimum fee rate in LBC/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee
MinRelayTxFee float64 `json:"minrelaytxfee"` // Current minimum relay fee for transactions
UnbroadcastCount int64 `json:"unbroadcastcount"` // Current number of transactions that haven't passed initial broadcast yet
}
// NetworksResult models the networks data from the getnetworkinfo command.
@ -428,6 +442,9 @@ type ScriptPubKeyResult struct {
Hex string `json:"hex,omitempty"`
ReqSigs int32 `json:"reqSigs,omitempty"`
Type string `json:"type"`
SubType string `json:"subtype"`
IsClaim bool `json:"isclaim"`
IsSupport bool `json:"issupport"`
Addresses []string `json:"addresses,omitempty"`
}
@ -586,6 +603,8 @@ func (v *Vin) MarshalJSON() ([]byte, error) {
type PrevOut struct {
Addresses []string `json:"addresses,omitempty"`
Value float64 `json:"value"`
IsClaim bool `json:"isclaim"`
IsSupport bool `json:"issupport"`
}
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
@ -704,6 +723,15 @@ type InfoChainResult struct {
Errors string `json:"errors"`
}
// ListBannedResult models the data returned from the listbanned command.
type ListBannedResult struct {
Address string `json:"address"`
BanCreated int64 `json:"ban_created"`
BannedUntil int64 `json:"banned_until"`
BanDuration int64 `json:"ban_duration"`
TimeRemaining int64 `json:"time_remaining"`
}
// TxRawResult models the data from the getrawtransaction command.
type TxRawResult struct {
Hex string `json:"hex"`

View file

@ -9,10 +9,10 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil"
"github.com/davecgh/go-spew/spew"
"github.com/lbryio/lbcd/btcjson"
"github.com/lbryio/lbcd/chaincfg/chainhash"
btcutil "github.com/lbryio/lbcutil"
)
// TestChainSvrCustomResults ensures any results that have custom marshalling
@ -70,7 +70,7 @@ func TestChainSvrCustomResults(t *testing.T) {
},
Sequence: 4294967295,
},
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0},"sequence":4294967295}`,
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0,"isclaim":false,"issupport":false},"sequence":4294967295}`,
},
}

View file

@ -12,7 +12,7 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/btcjson"
)
// TestChainSvrWsCmds tests all of the chain server websocket-specific commands

View file

@ -12,7 +12,7 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/btcjson"
)
// TestChainSvrWsNtfns tests all of the chain server websocket-specific

View file

@ -9,7 +9,7 @@ import (
"encoding/json"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/btcjson"
)
// TestChainSvrWsResults ensures any results that have custom marshalling

97
btcjson/claimcmds.go Normal file
View file

@ -0,0 +1,97 @@
package btcjson
func init() {
// No special flags for commands in this file.
flags := UsageFlag(0)
MustRegisterCmd("getchangesinblock", (*GetChangesInBlockCmd)(nil), flags)
MustRegisterCmd("getclaimsforname", (*GetClaimsForNameCmd)(nil), flags)
MustRegisterCmd("getclaimsfornamebyid", (*GetClaimsForNameByIDCmd)(nil), flags)
MustRegisterCmd("getclaimsfornamebybid", (*GetClaimsForNameByBidCmd)(nil), flags)
MustRegisterCmd("getclaimsfornamebyseq", (*GetClaimsForNameBySeqCmd)(nil), flags)
MustRegisterCmd("normalize", (*GetNormalizedCmd)(nil), flags)
}
// optional inputs are required to be pointers, but they support things like `jsonrpcdefault:"false"`
// optional inputs have to be at the bottom of the struct
// optional outputs require ",omitempty"
// traditional bitcoin fields are all lowercase
type GetChangesInBlockCmd struct {
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
}
type GetChangesInBlockResult struct {
Hash string `json:"hash"`
Height int32 `json:"height"`
Names []string `json:"names"`
}
type GetClaimsForNameCmd struct {
Name string `json:"name"`
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
}
type GetClaimsForNameByIDCmd struct {
Name string `json:"name"`
PartialClaimIDs []string `json:"partialclaimids"`
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
}
type GetClaimsForNameByBidCmd struct {
Name string `json:"name"`
Bids []int32 `json:"bids"`
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
}
type GetClaimsForNameBySeqCmd struct {
Name string `json:"name"`
Sequences []int32 `json:"sequences" jsonrpcusage:"[sequence,...]"`
HashOrHeight *string `json:"hashorheight" jsonrpcdefault:""`
IncludeValues *bool `json:"includevalues" jsonrpcdefault:"false"`
}
type GetClaimsForNameResult struct {
Hash string `json:"hash"`
Height int32 `json:"height"`
LastTakeoverHeight int32 `json:"lasttakeoverheight"`
NormalizedName string `json:"normalizedname"`
Claims []ClaimResult `json:"claims"`
// UnclaimedSupports []SupportResult `json:"supportswithoutclaim"` how would this work with other constraints?
}
type SupportResult struct {
TXID string `json:"txid"`
N uint32 `json:"n"`
Height int32 `json:"height"`
ValidAtHeight int32 `json:"validatheight"`
Amount int64 `json:"amount"`
Address string `json:"address,omitempty"`
Value string `json:"value,omitempty"`
}
type ClaimResult struct {
ClaimID string `json:"claimid"`
TXID string `json:"txid"`
N uint32 `json:"n"`
Bid int32 `json:"bid"`
Sequence int32 `json:"sequence"`
Height int32 `json:"height"`
ValidAtHeight int32 `json:"validatheight"`
Amount int64 `json:"amount"`
EffectiveAmount int64 `json:"effectiveamount"`
Supports []SupportResult `json:"supports,omitempty"`
Address string `json:"address,omitempty"`
Value string `json:"value,omitempty"`
}
type GetNormalizedCmd struct {
Name string `json:"name"`
}
type GetNormalizedResult struct {
NormalizedName string `json:"normalizedname"`
}

View file

@ -8,7 +8,7 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/btcjson"
)
// TestCmdMethod tests the CmdMethod function to ensure it retunrs the expected

View file

@ -134,6 +134,16 @@ func UnmarshalCmd(r *Request) (interface{}, error) {
// Unmarshal the parameter into the struct field.
concreteVal := rvf.Addr().Interface()
if err := json.Unmarshal(r.Params[i], &concreteVal); err != nil {
// Parse Integer into Bool for compatibility with lbrycrd.
if rvf.Kind() == reflect.Ptr &&
rvf.Elem().Type().Kind() == reflect.Bool {
boolInt, errBoolInt := strconv.Atoi(string(r.Params[i]))
if errBoolInt == nil {
rvf.Elem().SetBool(boolInt != 0)
continue
}
}
// The most common error is the wrong type, so
// explicitly detect that error and make it nicer.
fieldName := strings.ToLower(rt.Field(i).Name)

View file

@ -10,7 +10,7 @@ import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/btcjson"
)
// TestAssignField tests the assignField function handles supported combinations
@ -557,7 +557,7 @@ func TestUnmarshalCmdErrors(t *testing.T) {
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getblock",
Params: []json.RawMessage{[]byte("1")},
Params: []json.RawMessage{[]byte("1.0")},
ID: nil,
},
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
@ -591,3 +591,84 @@ func TestUnmarshalCmdErrors(t *testing.T) {
}
}
}
// TestUnmarshalCmdBoolParams tests the parsing of boolean paramers of the UnmarshalCmd function.
func TestUnmarshalCmdBoolParams(t *testing.T) {
t.Parallel()
txid := []byte(`"ab91c149aff2b37a4a1856e9935ea623c973f47886d032ed7511ad8ca37855bb"`)
tests := []struct {
name string
request btcjson.Request
expect bool
}{
{
name: "parse true",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("true")},
ID: nil,
},
expect: true,
},
{
name: "parse false",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("false")},
ID: nil,
},
expect: false,
},
{
name: "parse integer 0 to false",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("0")},
ID: nil,
},
expect: false,
},
{
name: "parse integer 1 to true",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("1")},
ID: nil,
},
expect: true,
},
{
name: "parse integer 100 to true",
request: btcjson.Request{
Jsonrpc: btcjson.RpcVersion1,
Method: "getrawtransaction",
Params: []json.RawMessage{txid, []byte("100")},
ID: nil,
},
expect: true,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
cmd, err := btcjson.UnmarshalCmd(&test.request)
if err != nil {
t.Errorf("Test #%d (%s) error - got %T (%v)", i, test.name,
err, err)
continue
}
cc := cmd.(*btcjson.GetRawTransactionCmd)
verbose := *cc.Verbose
if verbose != test.expect {
t.Errorf("Test #%d (%s) got %t, want %v", i, test.name,
verbose, test.expect)
continue
}
}
}

View file

@ -5,7 +5,7 @@
/*
Package btcjson provides primitives for working with the bitcoin JSON-RPC API.
Overview
# Overview
When communicating via the JSON-RPC protocol, all of the commands need to be
marshalled to and from the the wire in the appropriate format. This package
@ -14,7 +14,7 @@ provides data structures and primitives to ease this process.
In addition, it also provides some additional features such as custom command
registration, command categorization, and reflection-based help generation.
JSON-RPC Protocol Overview
# JSON-RPC Protocol Overview
This information is not necessary in order to use this package, but it does
provide some intuition into what the marshalling and unmarshalling that is
@ -47,39 +47,39 @@ with it) doesn't always follow the spec and will sometimes return an error
string in the result field with a null error for certain commands. However,
for the most part, the error field will be set as described on failure.
Marshalling and Unmarshalling
# Marshalling and Unmarshalling
Based upon the discussion above, it should be easy to see how the types of this
package map into the required parts of the protocol
- Request Objects (type Request)
- Commands (type <Foo>Cmd)
- Notifications (type <Foo>Ntfn)
- Commands (type <Foo>Cmd)
- Notifications (type <Foo>Ntfn)
- Response Objects (type Response)
- Result (type <Foo>Result)
- Result (type <Foo>Result)
To simplify the marshalling of the requests and responses, the MarshalCmd and
MarshalResponse functions are provided. They return the raw bytes ready to be
sent across the wire.
Unmarshalling a received Request object is a two step process:
1) Unmarshal the raw bytes into a Request struct instance via json.Unmarshal
2) Use UnmarshalCmd on the Result field of the unmarshalled Request to create
a concrete command or notification instance with all struct fields set
accordingly
1. Unmarshal the raw bytes into a Request struct instance via json.Unmarshal
2. Use UnmarshalCmd on the Result field of the unmarshalled Request to create
a concrete command or notification instance with all struct fields set
accordingly
This approach is used since it provides the caller with access to the additional
fields in the request that are not part of the command such as the ID.
Unmarshalling a received Response object is also a two step process:
1) Unmarhsal the raw bytes into a Response struct instance via json.Unmarshal
2) Depending on the ID, unmarshal the Result field of the unmarshalled
Response to create a concrete type instance
1. Unmarhsal the raw bytes into a Response struct instance via json.Unmarshal
2. Depending on the ID, unmarshal the Result field of the unmarshalled
Response to create a concrete type instance
As above, this approach is used since it provides the caller with access to the
fields in the response such as the ID and Error.
Command Creation
# Command Creation
This package provides two approaches for creating a new command. This first,
and preferred, method is to use one of the New<Foo>Cmd functions. This allows
@ -93,7 +93,7 @@ obviously, run-time which means any mistakes won't be found until the code is
actually executed. However, it is quite useful for user-supplied commands
that are intentionally dynamic.
Custom Command Registration
# Custom Command Registration
The command handling of this package is built around the concept of registered
commands. This is true for the wide variety of commands already provided by the
@ -104,7 +104,7 @@ function for this purpose.
A list of all registered methods can be obtained with the RegisteredCmdMethods
function.
Command Inspection
# Command Inspection
All registered commands are registered with flags that identify information such
as whether the command applies to a chain server, wallet server, or is a
@ -112,7 +112,7 @@ notification along with the method name to use. These flags can be obtained
with the MethodUsageFlags flags, and the method can be obtained with the
CmdMethod function.
Help Generation
# Help Generation
To facilitate providing consistent help to users of the RPC server, this package
exposes the GenerateHelp and function which uses reflection on registered
@ -122,7 +122,7 @@ generate the final help text.
In addition, the MethodUsageText function is provided to generate consistent
one-line usage for registered commands and notifications using reflection.
Errors
# Errors
There are 2 distinct type of errors supported by this package:

View file

@ -7,7 +7,7 @@ package btcjson_test
import (
"testing"
"github.com/btcsuite/btcd/btcjson"
"github.com/lbryio/lbcd/btcjson"
)
// TestErrorCodeStringer tests the stringized output for the ErrorCode type.

Some files were not shown because too many files have changed in this diff Show more