From d301c635961ab04d4aa4f2013a5328ff11d1fbf3 Mon Sep 17 00:00:00 2001 From: Manu Herrera Date: Tue, 1 Oct 2019 12:22:30 -0300 Subject: [PATCH] Release v0.1.0 --- .gitignore | 12 +- address_generator.go | 103 + blockchain_scanner.go | 277 ++ go.mod | 15 + go.sum | 221 + keys_generator.go | 31 + recovery_tool.go | 347 ++ vendor/github.com/aead/siphash/.gitignore | 25 + vendor/github.com/aead/siphash/.travis.yml | 15 + vendor/github.com/aead/siphash/LICENSE | 21 + vendor/github.com/aead/siphash/README.md | 55 + vendor/github.com/aead/siphash/siphash.go | 157 + vendor/github.com/aead/siphash/siphash128.go | 106 + vendor/github.com/aead/siphash/siphash_386.go | 31 + vendor/github.com/aead/siphash/siphash_386.s | 65 + .../github.com/aead/siphash/siphash_amd64.go | 18 + .../github.com/aead/siphash/siphash_amd64.s | 49 + .../aead/siphash/siphash_generic.go | 188 + vendor/github.com/aead/siphash/siphash_ref.go | 19 + vendor/github.com/btcsuite/btcd/LICENSE | 16 + .../btcsuite/btcd/addrmgr/addrmanager.go | 1151 ++++++ .../btcsuite/btcd/addrmgr/cov_report.sh | 17 + .../github.com/btcsuite/btcd/addrmgr/doc.go | 38 + .../btcsuite/btcd/addrmgr/knownaddress.go | 102 + .../github.com/btcsuite/btcd/addrmgr/log.go | 32 + .../btcsuite/btcd/addrmgr/network.go | 281 ++ .../btcsuite/btcd/addrmgr/test_coverage.txt | 62 + .../btcsuite/btcd/blockchain/README.md | 103 + .../btcsuite/btcd/blockchain/accept.go | 92 + .../btcsuite/btcd/blockchain/blockindex.go | 348 ++ .../btcsuite/btcd/blockchain/chain.go | 1803 ++++++++ .../btcsuite/btcd/blockchain/chainio.go | 1416 +++++++ .../btcsuite/btcd/blockchain/chainview.go | 423 ++ .../btcsuite/btcd/blockchain/checkpoints.go | 261 ++ .../btcsuite/btcd/blockchain/compress.go | 586 +++ .../btcsuite/btcd/blockchain/difficulty.go | 312 ++ .../btcsuite/btcd/blockchain/doc.go | 81 + .../btcsuite/btcd/blockchain/error.go | 298 ++ .../btcsuite/btcd/blockchain/log.go | 30 + .../btcsuite/btcd/blockchain/mediantime.go | 218 + .../btcsuite/btcd/blockchain/merkle.go | 265 ++ .../btcsuite/btcd/blockchain/notifications.go | 81 + .../btcsuite/btcd/blockchain/process.go | 244 ++ .../btcsuite/btcd/blockchain/scriptval.go | 319 ++ .../btcd/blockchain/thresholdstate.go | 356 ++ .../btcsuite/btcd/blockchain/timesorter.go | 27 + .../btcsuite/btcd/blockchain/upgrade.go | 604 +++ .../btcsuite/btcd/blockchain/utxoviewpoint.go | 642 +++ .../btcsuite/btcd/blockchain/validate.go | 1279 ++++++ .../btcsuite/btcd/blockchain/versionbits.go | 301 ++ .../btcsuite/btcd/blockchain/weight.go | 117 + .../github.com/btcsuite/btcd/btcec/README.md | 68 + .../github.com/btcsuite/btcd/btcec/btcec.go | 958 +++++ .../btcsuite/btcd/btcec/ciphering.go | 216 + vendor/github.com/btcsuite/btcd/btcec/doc.go | 21 + .../github.com/btcsuite/btcd/btcec/field.go | 1223 ++++++ .../btcsuite/btcd/btcec/genprecomps.go | 63 + .../btcsuite/btcd/btcec/gensecp256k1.go | 203 + .../btcsuite/btcd/btcec/precompute.go | 67 + .../github.com/btcsuite/btcd/btcec/privkey.go | 73 + .../github.com/btcsuite/btcd/btcec/pubkey.go | 192 + .../btcsuite/btcd/btcec/secp256k1.go | 10 + .../btcsuite/btcd/btcec/signature.go | 540 +++ .../btcsuite/btcd/btcjson/CONTRIBUTORS | 16 + .../btcsuite/btcd/btcjson/README.md | 70 + .../btcsuite/btcd/btcjson/btcdextcmds.go | 138 + .../btcsuite/btcd/btcjson/btcdextresults.go | 20 + .../btcsuite/btcd/btcjson/btcwalletextcmds.go | 106 + .../btcsuite/btcd/btcjson/chainsvrcmds.go | 828 ++++ .../btcsuite/btcd/btcjson/chainsvrresults.go | 550 +++ .../btcsuite/btcd/btcjson/chainsvrwscmds.go | 241 ++ .../btcsuite/btcd/btcjson/chainsvrwsntfns.go | 304 ++ .../btcd/btcjson/chainsvrwsresults.go | 21 + .../btcsuite/btcd/btcjson/cmdinfo.go | 249 ++ .../btcsuite/btcd/btcjson/cmdparse.go | 550 +++ .../github.com/btcsuite/btcd/btcjson/doc.go | 146 + .../github.com/btcsuite/btcd/btcjson/error.go | 111 + .../github.com/btcsuite/btcd/btcjson/help.go | 560 +++ .../btcsuite/btcd/btcjson/helpers.go | 77 + .../btcsuite/btcd/btcjson/jsonrpc.go | 150 + .../btcsuite/btcd/btcjson/jsonrpcerr.go | 88 + .../btcsuite/btcd/btcjson/register.go | 292 ++ .../btcsuite/btcd/btcjson/walletsvrcmds.go | 699 ++++ .../btcsuite/btcd/btcjson/walletsvrresults.go | 161 + .../btcsuite/btcd/btcjson/walletsvrwscmds.go | 128 + .../btcsuite/btcd/btcjson/walletsvrwsntfns.go | 95 + .../btcsuite/btcd/chaincfg/README.md | 85 + .../btcd/chaincfg/chainhash/README.md | 41 + .../btcsuite/btcd/chaincfg/chainhash/doc.go | 5 + .../btcsuite/btcd/chaincfg/chainhash/hash.go | 128 + .../btcd/chaincfg/chainhash/hashfuncs.go | 33 + .../github.com/btcsuite/btcd/chaincfg/doc.go | 61 + .../btcsuite/btcd/chaincfg/genesis.go | 172 + .../btcsuite/btcd/chaincfg/params.go | 712 ++++ .../btcsuite/btcd/connmgr/README.md | 37 + .../btcsuite/btcd/connmgr/connmanager.go | 577 +++ .../github.com/btcsuite/btcd/connmgr/doc.go | 14 + .../btcsuite/btcd/connmgr/dynamicbanscore.go | 146 + .../github.com/btcsuite/btcd/connmgr/log.go | 30 + .../github.com/btcsuite/btcd/connmgr/seed.go | 75 + .../github.com/btcsuite/btcd/connmgr/tor.go | 129 + .../btcsuite/btcd/database/README.md | 57 + .../github.com/btcsuite/btcd/database/doc.go | 91 + .../btcsuite/btcd/database/driver.go | 89 + .../btcsuite/btcd/database/error.go | 197 + .../btcsuite/btcd/database/interface.go | 466 +++ .../github.com/btcsuite/btcd/database/log.go | 37 + .../github.com/btcsuite/btcd/peer/README.md | 73 + vendor/github.com/btcsuite/btcd/peer/doc.go | 150 + vendor/github.com/btcsuite/btcd/peer/log.go | 227 ++ .../btcsuite/btcd/peer/mruinvmap.go | 127 + .../btcsuite/btcd/peer/mrunoncemap.go | 125 + vendor/github.com/btcsuite/btcd/peer/peer.go | 2280 +++++++++++ .../btcsuite/btcd/rpcclient/CONTRIBUTORS | 13 + .../btcsuite/btcd/rpcclient/README.md | 56 + .../btcsuite/btcd/rpcclient/chain.go | 929 +++++ .../github.com/btcsuite/btcd/rpcclient/doc.go | 178 + .../btcsuite/btcd/rpcclient/extensions.go | 473 +++ .../btcsuite/btcd/rpcclient/infrastructure.go | 1334 ++++++ .../github.com/btcsuite/btcd/rpcclient/log.go | 47 + .../btcsuite/btcd/rpcclient/mining.go | 417 ++ .../github.com/btcsuite/btcd/rpcclient/net.go | 319 ++ .../btcsuite/btcd/rpcclient/notify.go | 1357 ++++++ .../btcsuite/btcd/rpcclient/rawrequest.go | 78 + .../btcd/rpcclient/rawtransactions.go | 664 +++ .../btcsuite/btcd/rpcclient/wallet.go | 2279 +++++++++++ .../btcsuite/btcd/txscript/README.md | 63 + .../btcsuite/btcd/txscript/consensus.go | 13 + .../github.com/btcsuite/btcd/txscript/doc.go | 42 + .../btcsuite/btcd/txscript/engine.go | 1004 +++++ .../btcsuite/btcd/txscript/error.go | 453 +++ .../btcsuite/btcd/txscript/hashcache.go | 89 + .../github.com/btcsuite/btcd/txscript/log.go | 43 + .../btcsuite/btcd/txscript/opcode.go | 2447 +++++++++++ .../btcsuite/btcd/txscript/pkscript.go | 279 ++ .../btcsuite/btcd/txscript/script.go | 860 ++++ .../btcsuite/btcd/txscript/scriptbuilder.go | 274 ++ .../btcsuite/btcd/txscript/scriptnum.go | 225 + .../btcsuite/btcd/txscript/sigcache.go | 99 + .../github.com/btcsuite/btcd/txscript/sign.go | 464 +++ .../btcsuite/btcd/txscript/stack.go | 361 ++ .../btcsuite/btcd/txscript/standard.go | 707 ++++ .../github.com/btcsuite/btcd/wire/README.md | 113 + .../btcsuite/btcd/wire/blockheader.go | 128 + .../github.com/btcsuite/btcd/wire/common.go | 689 ++++ vendor/github.com/btcsuite/btcd/wire/doc.go | 162 + vendor/github.com/btcsuite/btcd/wire/error.go | 34 + .../github.com/btcsuite/btcd/wire/invvect.go | 86 + .../github.com/btcsuite/btcd/wire/message.go | 440 ++ .../github.com/btcsuite/btcd/wire/msgaddr.go | 143 + .../github.com/btcsuite/btcd/wire/msgalert.go | 407 ++ .../github.com/btcsuite/btcd/wire/msgblock.go | 290 ++ .../btcsuite/btcd/wire/msgcfcheckpt.go | 164 + .../btcsuite/btcd/wire/msgcfheaders.go | 180 + .../btcsuite/btcd/wire/msgcfilter.go | 119 + .../btcsuite/btcd/wire/msgfeefilter.go | 64 + .../btcsuite/btcd/wire/msgfilteradd.go | 81 + .../btcsuite/btcd/wire/msgfilterclear.go | 59 + .../btcsuite/btcd/wire/msgfilterload.go | 136 + .../btcsuite/btcd/wire/msggetaddr.go | 47 + .../btcsuite/btcd/wire/msggetblocks.go | 139 + .../btcsuite/btcd/wire/msggetcfcheckpt.go | 64 + .../btcsuite/btcd/wire/msggetcfheaders.go | 77 + .../btcsuite/btcd/wire/msggetcfilters.go | 81 + .../btcsuite/btcd/wire/msggetdata.go | 133 + .../btcsuite/btcd/wire/msggetheaders.go | 136 + .../btcsuite/btcd/wire/msgheaders.go | 136 + .../github.com/btcsuite/btcd/wire/msginv.go | 141 + .../btcsuite/btcd/wire/msgmempool.go | 60 + .../btcsuite/btcd/wire/msgmerkleblock.go | 159 + .../btcsuite/btcd/wire/msgnotfound.go | 110 + .../github.com/btcsuite/btcd/wire/msgping.go | 87 + .../github.com/btcsuite/btcd/wire/msgpong.go | 78 + .../btcsuite/btcd/wire/msgreject.go | 186 + .../btcsuite/btcd/wire/msgsendheaders.go | 60 + vendor/github.com/btcsuite/btcd/wire/msgtx.go | 1027 +++++ .../btcsuite/btcd/wire/msgverack.go | 46 + .../btcsuite/btcd/wire/msgversion.go | 269 ++ .../btcsuite/btcd/wire/netaddress.go | 149 + .../github.com/btcsuite/btcd/wire/protocol.go | 178 + vendor/github.com/btcsuite/btclog/.gitignore | 28 + vendor/github.com/btcsuite/btclog/.travis.yml | 13 + vendor/github.com/btcsuite/btclog/LICENSE | 15 + vendor/github.com/btcsuite/btclog/README.md | 40 + vendor/github.com/btcsuite/btclog/doc.go | 27 + vendor/github.com/btcsuite/btclog/goclean.sh | 37 + .../github.com/btcsuite/btclog/interface.go | 64 + vendor/github.com/btcsuite/btclog/log.go | 480 +++ vendor/github.com/btcsuite/btcutil/.gitignore | 28 + .../github.com/btcsuite/btcutil/.travis.yml | 15 + vendor/github.com/btcsuite/btcutil/LICENSE | 16 + vendor/github.com/btcsuite/btcutil/README.md | 50 + vendor/github.com/btcsuite/btcutil/address.go | 683 ++++ vendor/github.com/btcsuite/btcutil/amount.go | 122 + vendor/github.com/btcsuite/btcutil/appdata.go | 105 + .../btcsuite/btcutil/base58/README.md | 34 + .../btcsuite/btcutil/base58/alphabet.go | 49 + .../btcsuite/btcutil/base58/base58.go | 75 + .../btcsuite/btcutil/base58/base58check.go | 52 + .../btcsuite/btcutil/base58/cov_report.sh | 17 + .../github.com/btcsuite/btcutil/base58/doc.go | 29 + .../btcsuite/btcutil/base58/genalphabet.go | 79 + .../btcsuite/btcutil/bech32/README.md | 29 + .../btcsuite/btcutil/bech32/bech32.go | 252 ++ .../github.com/btcsuite/btcutil/bech32/doc.go | 15 + vendor/github.com/btcsuite/btcutil/block.go | 265 ++ vendor/github.com/btcsuite/btcutil/certgen.go | 144 + vendor/github.com/btcsuite/btcutil/const.go | 16 + .../github.com/btcsuite/btcutil/cov_report.sh | 17 + vendor/github.com/btcsuite/btcutil/doc.go | 46 + .../github.com/btcsuite/btcutil/gcs/README.md | 24 + .../btcsuite/btcutil/gcs/builder/builder.go | 371 ++ vendor/github.com/btcsuite/btcutil/gcs/doc.go | 24 + vendor/github.com/btcsuite/btcutil/gcs/gcs.go | 541 +++ vendor/github.com/btcsuite/btcutil/goclean.sh | 48 + vendor/github.com/btcsuite/btcutil/hash160.go | 23 + .../btcsuite/btcutil/hdkeychain/README.md | 59 + .../btcsuite/btcutil/hdkeychain/cov_report.sh | 17 + .../btcsuite/btcutil/hdkeychain/doc.go | 84 + .../btcutil/hdkeychain/extendedkey.go | 577 +++ .../btcutil/hdkeychain/test_coverage.txt | 20 + vendor/github.com/btcsuite/btcutil/net.go | 18 + .../github.com/btcsuite/btcutil/net_noop.go | 19 + .../btcsuite/btcutil/test_coverage.txt | 72 + vendor/github.com/btcsuite/btcutil/tx.go | 124 + vendor/github.com/btcsuite/btcutil/wif.go | 169 + vendor/github.com/btcsuite/btcwallet/LICENSE | 16 + .../btcwallet/chain/bitcoind_client.go | 1341 ++++++ .../btcsuite/btcwallet/chain/bitcoind_conn.go | 397 ++ .../btcwallet/chain/block_filterer.go | 217 + .../btcsuite/btcwallet/chain/interface.go | 124 + .../btcsuite/btcwallet/chain/log.go | 56 + .../btcsuite/btcwallet/chain/neutrino.go | 747 ++++ .../btcsuite/btcwallet/chain/queue.go | 88 + .../btcsuite/btcwallet/chain/rpc.go | 461 +++ .../btcsuite/btcwallet/internal/zero/array.go | 17 + .../btcsuite/btcwallet/internal/zero/doc.go | 3 + .../btcsuite/btcwallet/internal/zero/slice.go | 34 + .../btcsuite/btcwallet/snacl/snacl.go | 248 ++ .../btcsuite/btcwallet/waddrmgr/README.md | 62 + .../btcsuite/btcwallet/waddrmgr/address.go | 648 +++ .../btcsuite/btcwallet/waddrmgr/cov_report.sh | 17 + .../btcsuite/btcwallet/waddrmgr/db.go | 2280 +++++++++++ .../btcsuite/btcwallet/waddrmgr/doc.go | 155 + .../btcsuite/btcwallet/waddrmgr/error.go | 219 + .../btcsuite/btcwallet/waddrmgr/log.go | 43 + .../btcsuite/btcwallet/waddrmgr/manager.go | 1822 +++++++++ .../btcsuite/btcwallet/waddrmgr/migrations.go | 412 ++ .../btcwallet/waddrmgr/scoped_manager.go | 1762 ++++++++ .../btcsuite/btcwallet/waddrmgr/sync.go | 135 + .../btcwallet/waddrmgr/test_coverage.txt | 126 + .../btcsuite/btcwallet/walletdb/LICENSE | 16 + .../btcsuite/btcwallet/walletdb/README.md | 75 + .../btcsuite/btcwallet/walletdb/bdb/README.md | 46 + .../btcsuite/btcwallet/walletdb/bdb/db.go | 356 ++ .../btcsuite/btcwallet/walletdb/bdb/doc.go | 25 + .../btcsuite/btcwallet/walletdb/bdb/driver.go | 66 + .../btcsuite/btcwallet/walletdb/cov_report.sh | 7 + .../btcsuite/btcwallet/walletdb/doc.go | 103 + .../btcsuite/btcwallet/walletdb/error.go | 80 + .../btcsuite/btcwallet/walletdb/go.mod | 11 + .../btcsuite/btcwallet/walletdb/go.sum | 10 + .../btcsuite/btcwallet/walletdb/interface.go | 304 ++ .../btcwallet/walletdb/migration/log.go | 43 + .../btcwallet/walletdb/migration/manager.go | 162 + .../btcwallet/walletdb/test_coverage.txt | 39 + .../btcsuite/btcwallet/wtxmgr/LICENSE | 16 + .../btcsuite/btcwallet/wtxmgr/README.md | 45 + .../btcsuite/btcwallet/wtxmgr/db.go | 1496 +++++++ .../btcsuite/btcwallet/wtxmgr/doc.go | 31 + .../btcsuite/btcwallet/wtxmgr/error.go | 97 + .../btcsuite/btcwallet/wtxmgr/go.mod | 10 + .../btcsuite/btcwallet/wtxmgr/go.sum | 56 + .../btcsuite/btcwallet/wtxmgr/kahnsort.go | 117 + .../btcsuite/btcwallet/wtxmgr/log.go | 47 + .../btcsuite/btcwallet/wtxmgr/migrations.go | 110 + .../btcsuite/btcwallet/wtxmgr/query.go | 455 +++ .../btcsuite/btcwallet/wtxmgr/tx.go | 925 +++++ .../btcsuite/btcwallet/wtxmgr/unconfirmed.go | 222 + vendor/github.com/btcsuite/go-socks/LICENSE | 25 + .../btcsuite/go-socks/socks/addr.go | 21 + .../btcsuite/go-socks/socks/conn.go | 54 + .../btcsuite/go-socks/socks/dial.go | 269 ++ .../github.com/btcsuite/websocket/.gitignore | 22 + .../github.com/btcsuite/websocket/.travis.yml | 6 + vendor/github.com/btcsuite/websocket/AUTHORS | 8 + vendor/github.com/btcsuite/websocket/LICENSE | 22 + .../github.com/btcsuite/websocket/README.md | 63 + .../github.com/btcsuite/websocket/client.go | 235 ++ vendor/github.com/btcsuite/websocket/conn.go | 825 ++++ vendor/github.com/btcsuite/websocket/doc.go | 148 + vendor/github.com/btcsuite/websocket/json.go | 49 + .../github.com/btcsuite/websocket/server.go | 247 ++ vendor/github.com/btcsuite/websocket/util.go | 44 + vendor/github.com/coreos/bbolt/.gitignore | 5 + vendor/github.com/coreos/bbolt/.travis.yml | 17 + vendor/github.com/coreos/bbolt/LICENSE | 20 + vendor/github.com/coreos/bbolt/Makefile | 38 + vendor/github.com/coreos/bbolt/README.md | 954 +++++ vendor/github.com/coreos/bbolt/bolt_386.go | 10 + vendor/github.com/coreos/bbolt/bolt_amd64.go | 10 + vendor/github.com/coreos/bbolt/bolt_arm.go | 28 + vendor/github.com/coreos/bbolt/bolt_arm64.go | 12 + vendor/github.com/coreos/bbolt/bolt_linux.go | 10 + .../github.com/coreos/bbolt/bolt_mips64x.go | 12 + vendor/github.com/coreos/bbolt/bolt_mipsx.go | 12 + .../github.com/coreos/bbolt/bolt_openbsd.go | 27 + vendor/github.com/coreos/bbolt/bolt_ppc.go | 12 + vendor/github.com/coreos/bbolt/bolt_ppc64.go | 12 + .../github.com/coreos/bbolt/bolt_ppc64le.go | 12 + .../github.com/coreos/bbolt/bolt_riscv64.go | 12 + vendor/github.com/coreos/bbolt/bolt_s390x.go | 12 + vendor/github.com/coreos/bbolt/bolt_unix.go | 93 + .../coreos/bbolt/bolt_unix_solaris.go | 88 + .../github.com/coreos/bbolt/bolt_windows.go | 141 + .../github.com/coreos/bbolt/boltsync_unix.go | 8 + vendor/github.com/coreos/bbolt/bucket.go | 775 ++++ vendor/github.com/coreos/bbolt/cursor.go | 396 ++ vendor/github.com/coreos/bbolt/db.go | 1174 ++++++ vendor/github.com/coreos/bbolt/doc.go | 44 + vendor/github.com/coreos/bbolt/errors.go | 71 + vendor/github.com/coreos/bbolt/freelist.go | 392 ++ .../github.com/coreos/bbolt/freelist_hmap.go | 178 + vendor/github.com/coreos/bbolt/node.go | 604 +++ vendor/github.com/coreos/bbolt/page.go | 197 + vendor/github.com/coreos/bbolt/tx.go | 726 ++++ vendor/github.com/davecgh/go-spew/LICENSE | 15 + .../github.com/davecgh/go-spew/spew/bypass.go | 145 + .../davecgh/go-spew/spew/bypasssafe.go | 38 + .../github.com/davecgh/go-spew/spew/common.go | 341 ++ .../github.com/davecgh/go-spew/spew/config.go | 306 ++ vendor/github.com/davecgh/go-spew/spew/doc.go | 211 + .../github.com/davecgh/go-spew/spew/dump.go | 509 +++ .../github.com/davecgh/go-spew/spew/format.go | 419 ++ .../github.com/davecgh/go-spew/spew/spew.go | 148 + .../github.com/go-errors/errors/.travis.yml | 5 + .../github.com/go-errors/errors/LICENSE.MIT | 7 + vendor/github.com/go-errors/errors/README.md | 66 + vendor/github.com/go-errors/errors/cover.out | 89 + vendor/github.com/go-errors/errors/error.go | 217 + .../go-errors/errors/parse_panic.go | 127 + .../github.com/go-errors/errors/stackframe.go | 102 + vendor/github.com/golang/protobuf/AUTHORS | 3 + .../github.com/golang/protobuf/CONTRIBUTORS | 3 + vendor/github.com/golang/protobuf/LICENSE | 28 + .../github.com/golang/protobuf/proto/clone.go | 253 ++ .../golang/protobuf/proto/decode.go | 427 ++ .../golang/protobuf/proto/deprecated.go | 63 + .../golang/protobuf/proto/discard.go | 350 ++ .../golang/protobuf/proto/encode.go | 203 + .../github.com/golang/protobuf/proto/equal.go | 301 ++ .../golang/protobuf/proto/extensions.go | 607 +++ .../github.com/golang/protobuf/proto/lib.go | 965 +++++ .../golang/protobuf/proto/message_set.go | 181 + .../golang/protobuf/proto/pointer_reflect.go | 360 ++ .../golang/protobuf/proto/pointer_unsafe.go | 313 ++ .../golang/protobuf/proto/properties.go | 544 +++ .../golang/protobuf/proto/table_marshal.go | 2776 +++++++++++++ .../golang/protobuf/proto/table_merge.go | 654 +++ .../golang/protobuf/proto/table_unmarshal.go | 2053 ++++++++++ .../github.com/golang/protobuf/proto/text.go | 843 ++++ .../golang/protobuf/proto/text_parser.go | 880 ++++ vendor/github.com/kkdai/bstream/.gitignore | 2 + vendor/github.com/kkdai/bstream/.travis.yml | 15 + vendor/github.com/kkdai/bstream/LICENSE | 22 + vendor/github.com/kkdai/bstream/README.md | 61 + vendor/github.com/kkdai/bstream/bstream.go | 179 + vendor/github.com/lightninglabs/gozmq/LICENSE | 21 + .../github.com/lightninglabs/gozmq/README.md | 29 + vendor/github.com/lightninglabs/gozmq/go.mod | 3 + vendor/github.com/lightninglabs/gozmq/zmq.go | 462 +++ .../lightninglabs/neutrino/.gitignore | 30 + .../lightninglabs/neutrino/.travis.yml | 27 + .../github.com/lightninglabs/neutrino/LICENSE | 21 + .../lightninglabs/neutrino/README.md | 25 + .../lightninglabs/neutrino/banman/codec.go | 83 + .../lightninglabs/neutrino/banman/reason.go | 43 + .../lightninglabs/neutrino/banman/store.go | 221 + .../lightninglabs/neutrino/banman/util.go | 48 + .../neutrino/batch_spend_reporter.go | 267 ++ .../lightninglabs/neutrino/blockmanager.go | 2892 +++++++++++++ .../lightninglabs/neutrino/blockntfns/log.go | 43 + .../neutrino/blockntfns/manager.go | 353 ++ .../neutrino/blockntfns/notification.go | 105 + .../lightninglabs/neutrino/btcd_checkout.sh | 3 + .../lightninglabs/neutrino/cache/cache.go | 29 + .../neutrino/cache/cacheable_block.go | 14 + .../neutrino/cache/cacheable_filter.go | 28 + .../lightninglabs/neutrino/cache/lru/lru.go | 167 + .../neutrino/chainsync/filtercontrol.go | 75 + .../lightninglabs/neutrino/errors.go | 11 + .../lightninglabs/neutrino/filterdb/db.go | 202 + .../github.com/lightninglabs/neutrino/go.mod | 14 + .../github.com/lightninglabs/neutrino/go.sum | 94 + .../lightninglabs/neutrino/gotest.sh | 138 + .../lightninglabs/neutrino/headerfs/file.go | 189 + .../lightninglabs/neutrino/headerfs/index.go | 305 ++ .../lightninglabs/neutrino/headerfs/store.go | 939 +++++ .../neutrino/headerfs/truncate.go | 38 + .../neutrino/headerfs/truncate_windows.go | 56 + .../headerlist/bounded_header_list.go | 137 + .../neutrino/headerlist/header_list.go | 46 + .../lightninglabs/neutrino/headerlogger.go | 76 + .../github.com/lightninglabs/neutrino/log.go | 58 + .../lightninglabs/neutrino/mock_store.go | 82 + .../lightninglabs/neutrino/neutrino.go | 1561 +++++++ .../lightninglabs/neutrino/notifications.go | 318 ++ .../neutrino/pushtx/broadcaster.go | 290 ++ .../lightninglabs/neutrino/pushtx/error.go | 152 + .../lightninglabs/neutrino/pushtx/log.go | 43 + .../lightninglabs/neutrino/query.go | 1501 +++++++ .../lightninglabs/neutrino/rescan.go | 1382 +++++++ .../lightninglabs/neutrino/utxoscanner.go | 434 ++ .../github.com/lightningnetwork/lnd/LICENSE | 19 + .../lightningnetwork/lnd/lnwire/README.md | 18 + .../lnd/lnwire/accept_channel.go | 158 + .../lnd/lnwire/announcement_signatures.go | 108 + .../lnd/lnwire/channel_announcement.go | 160 + .../lightningnetwork/lnd/lnwire/channel_id.go | 91 + .../lnd/lnwire/channel_reestablish.go | 166 + .../lnd/lnwire/channel_update.go | 253 ++ .../lnd/lnwire/closing_signed.go | 88 + .../lightningnetwork/lnd/lnwire/commit_sig.go | 85 + .../lightningnetwork/lnd/lnwire/error.go | 127 + .../lightningnetwork/lnd/lnwire/features.go | 263 ++ .../lnd/lnwire/funding_created.go | 66 + .../lnd/lnwire/funding_locked.go | 83 + .../lnd/lnwire/funding_signed.go | 55 + .../lnd/lnwire/gossip_timestamp_range.go | 80 + .../lnd/lnwire/init_message.go | 67 + .../lightningnetwork/lnd/lnwire/lnwire.go | 857 ++++ .../lightningnetwork/lnd/lnwire/message.go | 296 ++ .../lightningnetwork/lnd/lnwire/msat.go | 45 + .../lightningnetwork/lnd/lnwire/netaddress.go | 54 + .../lnd/lnwire/node_announcement.go | 205 + .../lnd/lnwire/onion_error.go | 1292 ++++++ .../lnd/lnwire/open_channel.go | 202 + .../lightningnetwork/lnd/lnwire/ping.go | 67 + .../lightningnetwork/lnd/lnwire/pong.go | 63 + .../lnd/lnwire/query_channel_range.go | 77 + .../lnd/lnwire/query_short_chan_ids.go | 371 ++ .../lnd/lnwire/reply_channel_range.go | 84 + .../lnd/lnwire/reply_short_chan_ids_end.go | 74 + .../lnd/lnwire/revoke_and_ack.go | 83 + .../lnd/lnwire/short_channel_id.go | 48 + .../lightningnetwork/lnd/lnwire/shutdown.go | 81 + .../lightningnetwork/lnd/lnwire/signature.go | 128 + .../lnd/lnwire/update_add_htlc.go | 109 + .../lnd/lnwire/update_fail_htlc.go | 85 + .../lnd/lnwire/update_fail_malformed_htlc.go | 75 + .../lightningnetwork/lnd/lnwire/update_fee.go | 70 + .../lnd/lnwire/update_fulfill_htlc.go | 78 + .../lightningnetwork/lnd/queue/LICENSE | 19 + .../lightningnetwork/lnd/queue/gc_queue.go | 196 + .../lightningnetwork/lnd/queue/go.mod | 5 + .../lightningnetwork/lnd/queue/go.sum | 2 + .../lightningnetwork/lnd/queue/queue.go | 105 + .../lightningnetwork/lnd/ticker/LICENSE | 19 + .../lightningnetwork/lnd/ticker/force.go | 105 + .../lightningnetwork/lnd/ticker/go.mod | 1 + .../lightningnetwork/lnd/ticker/ticker.go | 126 + .../lightningnetwork/lnd/tor/README.md | 21 + .../lightningnetwork/lnd/tor/controller.go | 530 +++ .../lightningnetwork/lnd/tor/net.go | 104 + .../lightningnetwork/lnd/tor/onionaddr.go | 63 + .../lightningnetwork/lnd/tor/tor.go | 243 ++ .../lightningnetwork/lnd/zpay32/README.md | 22 + .../lnd/zpay32/amountunits.go | 162 + .../lightningnetwork/lnd/zpay32/bech32.go | 168 + .../lightningnetwork/lnd/zpay32/hophint.go | 43 + .../lightningnetwork/lnd/zpay32/invoice.go | 1097 +++++ vendor/github.com/miekg/dns/.gitignore | 4 + vendor/github.com/miekg/dns/.travis.yml | 20 + vendor/github.com/miekg/dns/AUTHORS | 1 + vendor/github.com/miekg/dns/CONTRIBUTORS | 10 + vendor/github.com/miekg/dns/COPYRIGHT | 9 + vendor/github.com/miekg/dns/LICENSE | 32 + vendor/github.com/miekg/dns/Makefile.fuzz | 33 + vendor/github.com/miekg/dns/README.md | 164 + vendor/github.com/miekg/dns/client.go | 507 +++ vendor/github.com/miekg/dns/clientconfig.go | 137 + .../github.com/miekg/dns/compress_generate.go | 189 + vendor/github.com/miekg/dns/dane.go | 43 + vendor/github.com/miekg/dns/defaults.go | 285 ++ vendor/github.com/miekg/dns/dns.go | 107 + vendor/github.com/miekg/dns/dnssec.go | 736 ++++ vendor/github.com/miekg/dns/dnssec_keygen.go | 156 + vendor/github.com/miekg/dns/dnssec_keyscan.go | 259 ++ vendor/github.com/miekg/dns/dnssec_privkey.go | 85 + vendor/github.com/miekg/dns/doc.go | 272 ++ vendor/github.com/miekg/dns/edns.go | 634 +++ vendor/github.com/miekg/dns/format.go | 87 + vendor/github.com/miekg/dns/fuzz.go | 23 + vendor/github.com/miekg/dns/generate.go | 159 + .../miekg/dns/internal/socket/cmsghdr.go | 7 + .../internal/socket/cmsghdr_linux_32bit.go | 20 + .../internal/socket/cmsghdr_linux_64bit.go | 20 + .../dns/internal/socket/cmsghdr_other.go | 13 + .../dns/internal/socket/controlmessage.go | 118 + .../miekg/dns/internal/socket/socket.go | 4 + .../miekg/dns/internal/socket/sys.go | 14 + vendor/github.com/miekg/dns/labels.go | 191 + vendor/github.com/miekg/dns/msg.go | 1148 ++++++ vendor/github.com/miekg/dns/msg_generate.go | 349 ++ vendor/github.com/miekg/dns/msg_helpers.go | 640 +++ vendor/github.com/miekg/dns/nsecx.go | 106 + vendor/github.com/miekg/dns/privaterr.go | 149 + vendor/github.com/miekg/dns/rawmsg.go | 49 + vendor/github.com/miekg/dns/reverse.go | 38 + vendor/github.com/miekg/dns/sanitize.go | 84 + vendor/github.com/miekg/dns/scan.go | 996 +++++ vendor/github.com/miekg/dns/scan_rr.go | 2153 ++++++++++ vendor/github.com/miekg/dns/scanner.go | 56 + vendor/github.com/miekg/dns/server.go | 713 ++++ vendor/github.com/miekg/dns/sig0.go | 218 + vendor/github.com/miekg/dns/singleinflight.go | 57 + vendor/github.com/miekg/dns/smimea.go | 47 + vendor/github.com/miekg/dns/tlsa.go | 47 + vendor/github.com/miekg/dns/tsig.go | 386 ++ vendor/github.com/miekg/dns/types.go | 1377 +++++++ vendor/github.com/miekg/dns/types_generate.go | 271 ++ vendor/github.com/miekg/dns/udp.go | 45 + vendor/github.com/miekg/dns/udp_linux.go | 220 + vendor/github.com/miekg/dns/udp_other.go | 17 + vendor/github.com/miekg/dns/udp_windows.go | 30 + vendor/github.com/miekg/dns/update.go | 106 + vendor/github.com/miekg/dns/xfr.go | 260 ++ vendor/github.com/miekg/dns/zcompress.go | 119 + vendor/github.com/miekg/dns/zmsg.go | 3619 +++++++++++++++++ vendor/github.com/miekg/dns/ztypes.go | 864 ++++ vendor/github.com/muun/libwallet/.gitignore | 17 + vendor/github.com/muun/libwallet/README.md | 16 + vendor/github.com/muun/libwallet/V1.go | 73 + vendor/github.com/muun/libwallet/V2.go | 106 + vendor/github.com/muun/libwallet/V3.go | 84 + vendor/github.com/muun/libwallet/address.go | 252 ++ vendor/github.com/muun/libwallet/aes.go | 70 + vendor/github.com/muun/libwallet/bip70.pb.go | 431 ++ vendor/github.com/muun/libwallet/bip70.proto | 44 + .../muun/libwallet/challenge_keys.go | 124 + .../muun/libwallet/challenge_public_key.go | 76 + .../muun/libwallet/derivationpath.go | 79 + vendor/github.com/muun/libwallet/go.mod | 12 + vendor/github.com/muun/libwallet/go.sum | 191 + .../github.com/muun/libwallet/hdkeycommon.go | 29 + .../github.com/muun/libwallet/hdprivatekey.go | 136 + .../github.com/muun/libwallet/hdpublickey.go | 96 + vendor/github.com/muun/libwallet/invoice.go | 67 + .../github.com/muun/libwallet/keycrypter.go | 168 + vendor/github.com/muun/libwallet/network.go | 34 + .../libwallet/partiallysignedtransaction.go | 149 + vendor/github.com/muun/libwallet/ripemd160.go | 15 + vendor/github.com/muun/libwallet/scrypt.go | 27 + vendor/github.com/muun/libwallet/segwit.go | 46 + .../muun/libwallet/submarineSwap.go | 215 + vendor/github.com/pkg/errors/.gitignore | 24 + vendor/github.com/pkg/errors/.travis.yml | 15 + vendor/github.com/pkg/errors/LICENSE | 23 + vendor/github.com/pkg/errors/README.md | 52 + vendor/github.com/pkg/errors/appveyor.yml | 32 + vendor/github.com/pkg/errors/errors.go | 282 ++ vendor/github.com/pkg/errors/stack.go | 147 + vendor/golang.org/x/crypto/AUTHORS | 3 + vendor/golang.org/x/crypto/CONTRIBUTORS | 3 + vendor/golang.org/x/crypto/LICENSE | 27 + vendor/golang.org/x/crypto/PATENTS | 22 + .../x/crypto/internal/subtle/aliasing.go | 32 + .../internal/subtle/aliasing_appengine.go | 35 + .../x/crypto/nacl/secretbox/secretbox.go | 173 + vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go | 77 + .../golang.org/x/crypto/poly1305/mac_noasm.go | 11 + .../golang.org/x/crypto/poly1305/poly1305.go | 83 + .../golang.org/x/crypto/poly1305/sum_amd64.go | 68 + .../golang.org/x/crypto/poly1305/sum_amd64.s | 148 + .../golang.org/x/crypto/poly1305/sum_arm.go | 22 + vendor/golang.org/x/crypto/poly1305/sum_arm.s | 427 ++ .../x/crypto/poly1305/sum_generic.go | 172 + .../golang.org/x/crypto/poly1305/sum_noasm.go | 16 + .../x/crypto/poly1305/sum_ppc64le.go | 68 + .../x/crypto/poly1305/sum_ppc64le.s | 247 ++ .../golang.org/x/crypto/poly1305/sum_s390x.go | 42 + .../golang.org/x/crypto/poly1305/sum_s390x.s | 378 ++ .../x/crypto/poly1305/sum_vmsl_s390x.s | 909 +++++ .../x/crypto/ripemd160/ripemd160.go | 124 + .../x/crypto/ripemd160/ripemd160block.go | 165 + .../x/crypto/salsa20/salsa/hsalsa20.go | 144 + .../x/crypto/salsa20/salsa/salsa208.go | 199 + .../x/crypto/salsa20/salsa/salsa20_amd64.go | 23 + .../x/crypto/salsa20/salsa/salsa20_amd64.s | 883 ++++ .../x/crypto/salsa20/salsa/salsa20_noasm.go | 14 + .../x/crypto/salsa20/salsa/salsa20_ref.go | 231 ++ vendor/golang.org/x/crypto/scrypt/scrypt.go | 213 + vendor/golang.org/x/net/AUTHORS | 3 + vendor/golang.org/x/net/CONTRIBUTORS | 3 + vendor/golang.org/x/net/LICENSE | 27 + vendor/golang.org/x/net/PATENTS | 22 + .../golang.org/x/net/internal/socks/client.go | 168 + .../golang.org/x/net/internal/socks/socks.go | 317 ++ vendor/golang.org/x/net/proxy/direct.go | 18 + vendor/golang.org/x/net/proxy/per_host.go | 140 + vendor/golang.org/x/net/proxy/proxy.go | 139 + vendor/golang.org/x/net/proxy/socks5.go | 36 + vendor/golang.org/x/sys/AUTHORS | 3 + vendor/golang.org/x/sys/CONTRIBUTORS | 3 + vendor/golang.org/x/sys/LICENSE | 27 + vendor/golang.org/x/sys/PATENTS | 22 + vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s | 17 + vendor/golang.org/x/sys/cpu/byteorder.go | 30 + vendor/golang.org/x/sys/cpu/cpu.go | 126 + vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go | 34 + vendor/golang.org/x/sys/cpu/cpu_arm.go | 9 + vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go | 21 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 16 + vendor/golang.org/x/sys/cpu/cpu_gccgo.c | 43 + vendor/golang.org/x/sys/cpu/cpu_gccgo.go | 26 + .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 22 + vendor/golang.org/x/sys/cpu/cpu_linux.go | 59 + .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 67 + .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 33 + .../golang.org/x/sys/cpu/cpu_linux_s390x.go | 161 + vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 11 + vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 11 + .../golang.org/x/sys/cpu/cpu_other_arm64.go | 11 + vendor/golang.org/x/sys/cpu/cpu_s390x.s | 57 + vendor/golang.org/x/sys/cpu/cpu_wasm.go | 15 + vendor/golang.org/x/sys/cpu/cpu_x86.go | 59 + vendor/golang.org/x/sys/cpu/cpu_x86.s | 27 + .../x/sys/cpu/syscall_aix_ppc64_gc.go | 36 + vendor/golang.org/x/sys/unix/.gitignore | 2 + vendor/golang.org/x/sys/unix/README.md | 173 + .../golang.org/x/sys/unix/affinity_linux.go | 86 + vendor/golang.org/x/sys/unix/aliases.go | 14 + vendor/golang.org/x/sys/unix/asm_aix_ppc64.s | 17 + vendor/golang.org/x/sys/unix/asm_darwin_386.s | 29 + .../golang.org/x/sys/unix/asm_darwin_amd64.s | 29 + vendor/golang.org/x/sys/unix/asm_darwin_arm.s | 30 + .../golang.org/x/sys/unix/asm_darwin_arm64.s | 30 + .../x/sys/unix/asm_dragonfly_amd64.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_386.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_amd64.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_arm.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_arm64.s | 29 + vendor/golang.org/x/sys/unix/asm_linux_386.s | 65 + .../golang.org/x/sys/unix/asm_linux_amd64.s | 57 + vendor/golang.org/x/sys/unix/asm_linux_arm.s | 56 + .../golang.org/x/sys/unix/asm_linux_arm64.s | 52 + .../golang.org/x/sys/unix/asm_linux_mips64x.s | 56 + .../golang.org/x/sys/unix/asm_linux_mipsx.s | 54 + .../golang.org/x/sys/unix/asm_linux_ppc64x.s | 44 + .../golang.org/x/sys/unix/asm_linux_riscv64.s | 54 + .../golang.org/x/sys/unix/asm_linux_s390x.s | 56 + vendor/golang.org/x/sys/unix/asm_netbsd_386.s | 29 + .../golang.org/x/sys/unix/asm_netbsd_amd64.s | 29 + vendor/golang.org/x/sys/unix/asm_netbsd_arm.s | 29 + .../golang.org/x/sys/unix/asm_netbsd_arm64.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_386.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_amd64.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_arm.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_arm64.s | 29 + .../golang.org/x/sys/unix/asm_solaris_amd64.s | 17 + .../golang.org/x/sys/unix/bluetooth_linux.go | 35 + vendor/golang.org/x/sys/unix/cap_freebsd.go | 195 + vendor/golang.org/x/sys/unix/constants.go | 13 + vendor/golang.org/x/sys/unix/dev_aix_ppc.go | 27 + vendor/golang.org/x/sys/unix/dev_aix_ppc64.go | 29 + vendor/golang.org/x/sys/unix/dev_darwin.go | 24 + vendor/golang.org/x/sys/unix/dev_dragonfly.go | 30 + vendor/golang.org/x/sys/unix/dev_freebsd.go | 30 + vendor/golang.org/x/sys/unix/dev_linux.go | 42 + vendor/golang.org/x/sys/unix/dev_netbsd.go | 29 + vendor/golang.org/x/sys/unix/dev_openbsd.go | 29 + vendor/golang.org/x/sys/unix/dirent.go | 102 + vendor/golang.org/x/sys/unix/endian_big.go | 9 + vendor/golang.org/x/sys/unix/endian_little.go | 9 + vendor/golang.org/x/sys/unix/env_unix.go | 31 + .../x/sys/unix/errors_freebsd_386.go | 227 ++ .../x/sys/unix/errors_freebsd_amd64.go | 227 ++ .../x/sys/unix/errors_freebsd_arm.go | 226 + vendor/golang.org/x/sys/unix/fcntl.go | 32 + vendor/golang.org/x/sys/unix/fcntl_darwin.go | 18 + .../x/sys/unix/fcntl_linux_32bit.go | 13 + vendor/golang.org/x/sys/unix/gccgo.go | 62 + vendor/golang.org/x/sys/unix/gccgo_c.c | 39 + .../x/sys/unix/gccgo_linux_amd64.go | 20 + vendor/golang.org/x/sys/unix/ioctl.go | 65 + vendor/golang.org/x/sys/unix/mkall.sh | 227 ++ vendor/golang.org/x/sys/unix/mkasm_darwin.go | 61 + vendor/golang.org/x/sys/unix/mkerrors.sh | 670 +++ vendor/golang.org/x/sys/unix/mkpost.go | 122 + vendor/golang.org/x/sys/unix/mksyscall.go | 407 ++ .../x/sys/unix/mksyscall_aix_ppc.go | 415 ++ .../x/sys/unix/mksyscall_aix_ppc64.go | 614 +++ .../x/sys/unix/mksyscall_solaris.go | 335 ++ .../golang.org/x/sys/unix/mksysctl_openbsd.go | 355 ++ vendor/golang.org/x/sys/unix/mksysnum.go | 190 + vendor/golang.org/x/sys/unix/pagesize_unix.go | 15 + .../golang.org/x/sys/unix/pledge_openbsd.go | 163 + vendor/golang.org/x/sys/unix/race.go | 30 + vendor/golang.org/x/sys/unix/race0.go | 25 + .../x/sys/unix/readdirent_getdents.go | 12 + .../x/sys/unix/readdirent_getdirentries.go | 19 + .../golang.org/x/sys/unix/sockcmsg_linux.go | 36 + vendor/golang.org/x/sys/unix/sockcmsg_unix.go | 120 + vendor/golang.org/x/sys/unix/str.go | 26 + vendor/golang.org/x/sys/unix/syscall.go | 53 + vendor/golang.org/x/sys/unix/syscall_aix.go | 536 +++ .../golang.org/x/sys/unix/syscall_aix_ppc.go | 50 + .../x/sys/unix/syscall_aix_ppc64.go | 81 + vendor/golang.org/x/sys/unix/syscall_bsd.go | 618 +++ .../golang.org/x/sys/unix/syscall_darwin.go | 680 ++++ .../x/sys/unix/syscall_darwin_386.go | 65 + .../x/sys/unix/syscall_darwin_amd64.go | 65 + .../x/sys/unix/syscall_darwin_arm.go | 68 + .../x/sys/unix/syscall_darwin_arm64.go | 70 + .../x/sys/unix/syscall_darwin_libSystem.go | 31 + .../x/sys/unix/syscall_dragonfly.go | 519 +++ .../x/sys/unix/syscall_dragonfly_amd64.go | 52 + .../golang.org/x/sys/unix/syscall_freebsd.go | 877 ++++ .../x/sys/unix/syscall_freebsd_386.go | 52 + .../x/sys/unix/syscall_freebsd_amd64.go | 52 + .../x/sys/unix/syscall_freebsd_arm.go | 52 + .../x/sys/unix/syscall_freebsd_arm64.go | 52 + vendor/golang.org/x/sys/unix/syscall_linux.go | 1930 +++++++++ .../x/sys/unix/syscall_linux_386.go | 386 ++ .../x/sys/unix/syscall_linux_amd64.go | 190 + .../x/sys/unix/syscall_linux_amd64_gc.go | 13 + .../x/sys/unix/syscall_linux_arm.go | 287 ++ .../x/sys/unix/syscall_linux_arm64.go | 223 + .../golang.org/x/sys/unix/syscall_linux_gc.go | 14 + .../x/sys/unix/syscall_linux_gc_386.go | 16 + .../x/sys/unix/syscall_linux_gccgo_386.go | 30 + .../x/sys/unix/syscall_linux_gccgo_arm.go | 20 + .../x/sys/unix/syscall_linux_mips64x.go | 222 + .../x/sys/unix/syscall_linux_mipsx.go | 234 ++ .../x/sys/unix/syscall_linux_ppc64x.go | 152 + .../x/sys/unix/syscall_linux_riscv64.go | 226 + .../x/sys/unix/syscall_linux_s390x.go | 338 ++ .../x/sys/unix/syscall_linux_sparc64.go | 147 + .../golang.org/x/sys/unix/syscall_netbsd.go | 618 +++ .../x/sys/unix/syscall_netbsd_386.go | 33 + .../x/sys/unix/syscall_netbsd_amd64.go | 33 + .../x/sys/unix/syscall_netbsd_arm.go | 33 + .../x/sys/unix/syscall_netbsd_arm64.go | 33 + .../golang.org/x/sys/unix/syscall_openbsd.go | 412 ++ .../x/sys/unix/syscall_openbsd_386.go | 37 + .../x/sys/unix/syscall_openbsd_amd64.go | 37 + .../x/sys/unix/syscall_openbsd_arm.go | 37 + .../x/sys/unix/syscall_openbsd_arm64.go | 37 + .../golang.org/x/sys/unix/syscall_solaris.go | 724 ++++ .../x/sys/unix/syscall_solaris_amd64.go | 23 + vendor/golang.org/x/sys/unix/syscall_unix.go | 431 ++ .../golang.org/x/sys/unix/syscall_unix_gc.go | 15 + .../x/sys/unix/syscall_unix_gc_ppc64x.go | 24 + vendor/golang.org/x/sys/unix/timestruct.go | 82 + vendor/golang.org/x/sys/unix/types_aix.go | 237 ++ vendor/golang.org/x/sys/unix/types_darwin.go | 283 ++ .../golang.org/x/sys/unix/types_dragonfly.go | 263 ++ vendor/golang.org/x/sys/unix/types_freebsd.go | 400 ++ vendor/golang.org/x/sys/unix/types_netbsd.go | 290 ++ vendor/golang.org/x/sys/unix/types_openbsd.go | 283 ++ vendor/golang.org/x/sys/unix/types_solaris.go | 266 ++ .../golang.org/x/sys/unix/unveil_openbsd.go | 42 + vendor/golang.org/x/sys/unix/xattr_bsd.go | 240 ++ .../golang.org/x/sys/unix/zerrors_aix_ppc.go | 1374 +++++++ .../x/sys/unix/zerrors_aix_ppc64.go | 1375 +++++++ .../x/sys/unix/zerrors_darwin_386.go | 1783 ++++++++ .../x/sys/unix/zerrors_darwin_amd64.go | 1783 ++++++++ .../x/sys/unix/zerrors_darwin_arm.go | 1783 ++++++++ .../x/sys/unix/zerrors_darwin_arm64.go | 1783 ++++++++ .../x/sys/unix/zerrors_dragonfly_amd64.go | 1650 ++++++++ .../x/sys/unix/zerrors_freebsd_386.go | 1793 ++++++++ .../x/sys/unix/zerrors_freebsd_amd64.go | 1794 ++++++++ .../x/sys/unix/zerrors_freebsd_arm.go | 1802 ++++++++ .../x/sys/unix/zerrors_freebsd_arm64.go | 1794 ++++++++ .../x/sys/unix/zerrors_linux_386.go | 3091 ++++++++++++++ .../x/sys/unix/zerrors_linux_amd64.go | 3091 ++++++++++++++ .../x/sys/unix/zerrors_linux_arm.go | 3097 ++++++++++++++ .../x/sys/unix/zerrors_linux_arm64.go | 3082 ++++++++++++++ .../x/sys/unix/zerrors_linux_mips.go | 3098 ++++++++++++++ .../x/sys/unix/zerrors_linux_mips64.go | 3098 ++++++++++++++ .../x/sys/unix/zerrors_linux_mips64le.go | 3098 ++++++++++++++ .../x/sys/unix/zerrors_linux_mipsle.go | 3098 ++++++++++++++ .../x/sys/unix/zerrors_linux_ppc64.go | 3153 ++++++++++++++ .../x/sys/unix/zerrors_linux_ppc64le.go | 3153 ++++++++++++++ .../x/sys/unix/zerrors_linux_riscv64.go | 3078 ++++++++++++++ .../x/sys/unix/zerrors_linux_s390x.go | 3151 ++++++++++++++ .../x/sys/unix/zerrors_linux_sparc64.go | 3147 ++++++++++++++ .../x/sys/unix/zerrors_netbsd_386.go | 1772 ++++++++ .../x/sys/unix/zerrors_netbsd_amd64.go | 1762 ++++++++ .../x/sys/unix/zerrors_netbsd_arm.go | 1751 ++++++++ .../x/sys/unix/zerrors_netbsd_arm64.go | 1762 ++++++++ .../x/sys/unix/zerrors_openbsd_386.go | 1654 ++++++++ .../x/sys/unix/zerrors_openbsd_amd64.go | 1765 ++++++++ .../x/sys/unix/zerrors_openbsd_arm.go | 1656 ++++++++ .../x/sys/unix/zerrors_openbsd_arm64.go | 1789 ++++++++ .../x/sys/unix/zerrors_solaris_amd64.go | 1532 +++++++ .../golang.org/x/sys/unix/zptrace386_linux.go | 80 + .../golang.org/x/sys/unix/zptracearm_linux.go | 41 + .../x/sys/unix/zptracemips_linux.go | 50 + .../x/sys/unix/zptracemipsle_linux.go | 50 + .../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 1484 +++++++ .../x/sys/unix/zsyscall_aix_ppc64.go | 1442 +++++++ .../x/sys/unix/zsyscall_aix_ppc64_gc.go | 1192 ++++++ .../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 1070 +++++ .../x/sys/unix/zsyscall_darwin_386.1_11.go | 1810 +++++++++ .../x/sys/unix/zsyscall_darwin_386.go | 2505 ++++++++++++ .../x/sys/unix/zsyscall_darwin_386.s | 284 ++ .../x/sys/unix/zsyscall_darwin_amd64.1_11.go | 1810 +++++++++ .../x/sys/unix/zsyscall_darwin_amd64.go | 2520 ++++++++++++ .../x/sys/unix/zsyscall_darwin_amd64.s | 286 ++ .../x/sys/unix/zsyscall_darwin_arm.1_11.go | 1793 ++++++++ .../x/sys/unix/zsyscall_darwin_arm.go | 2468 +++++++++++ .../x/sys/unix/zsyscall_darwin_arm.s | 280 ++ .../x/sys/unix/zsyscall_darwin_arm64.1_11.go | 1793 ++++++++ .../x/sys/unix/zsyscall_darwin_arm64.go | 2468 +++++++++++ .../x/sys/unix/zsyscall_darwin_arm64.s | 280 ++ .../x/sys/unix/zsyscall_dragonfly_amd64.go | 1676 ++++++++ .../x/sys/unix/zsyscall_freebsd_386.go | 2025 +++++++++ .../x/sys/unix/zsyscall_freebsd_amd64.go | 2025 +++++++++ .../x/sys/unix/zsyscall_freebsd_arm.go | 2025 +++++++++ .../x/sys/unix/zsyscall_freebsd_arm64.go | 2025 +++++++++ .../x/sys/unix/zsyscall_linux_386.go | 2270 +++++++++++ .../x/sys/unix/zsyscall_linux_amd64.go | 2437 +++++++++++ .../x/sys/unix/zsyscall_linux_arm.go | 2407 +++++++++++ .../x/sys/unix/zsyscall_linux_arm64.go | 2294 +++++++++++ .../x/sys/unix/zsyscall_linux_mips.go | 2450 +++++++++++ .../x/sys/unix/zsyscall_linux_mips64.go | 2421 +++++++++++ .../x/sys/unix/zsyscall_linux_mips64le.go | 2421 +++++++++++ .../x/sys/unix/zsyscall_linux_mipsle.go | 2450 +++++++++++ .../x/sys/unix/zsyscall_linux_ppc64.go | 2499 ++++++++++++ .../x/sys/unix/zsyscall_linux_ppc64le.go | 2499 ++++++++++++ .../x/sys/unix/zsyscall_linux_riscv64.go | 2274 +++++++++++ .../x/sys/unix/zsyscall_linux_s390x.go | 2269 +++++++++++ .../x/sys/unix/zsyscall_linux_sparc64.go | 2432 +++++++++++ .../x/sys/unix/zsyscall_netbsd_386.go | 1826 +++++++++ .../x/sys/unix/zsyscall_netbsd_amd64.go | 1826 +++++++++ .../x/sys/unix/zsyscall_netbsd_arm.go | 1826 +++++++++ .../x/sys/unix/zsyscall_netbsd_arm64.go | 1826 +++++++++ .../x/sys/unix/zsyscall_openbsd_386.go | 1692 ++++++++ .../x/sys/unix/zsyscall_openbsd_amd64.go | 1692 ++++++++ .../x/sys/unix/zsyscall_openbsd_arm.go | 1692 ++++++++ .../x/sys/unix/zsyscall_openbsd_arm64.go | 1692 ++++++++ .../x/sys/unix/zsyscall_solaris_amd64.go | 1953 +++++++++ .../x/sys/unix/zsysctl_openbsd_386.go | 272 ++ .../x/sys/unix/zsysctl_openbsd_amd64.go | 270 ++ .../x/sys/unix/zsysctl_openbsd_arm.go | 272 ++ .../x/sys/unix/zsysctl_openbsd_arm64.go | 275 ++ .../x/sys/unix/zsysnum_darwin_386.go | 436 ++ .../x/sys/unix/zsysnum_darwin_amd64.go | 438 ++ .../x/sys/unix/zsysnum_darwin_arm.go | 436 ++ .../x/sys/unix/zsysnum_darwin_arm64.go | 436 ++ .../x/sys/unix/zsysnum_dragonfly_amd64.go | 315 ++ .../x/sys/unix/zsysnum_freebsd_386.go | 396 ++ .../x/sys/unix/zsysnum_freebsd_amd64.go | 396 ++ .../x/sys/unix/zsysnum_freebsd_arm.go | 396 ++ .../x/sys/unix/zsysnum_freebsd_arm64.go | 396 ++ .../x/sys/unix/zsysnum_linux_386.go | 432 ++ .../x/sys/unix/zsysnum_linux_amd64.go | 354 ++ .../x/sys/unix/zsysnum_linux_arm.go | 396 ++ .../x/sys/unix/zsysnum_linux_arm64.go | 299 ++ .../x/sys/unix/zsysnum_linux_mips.go | 417 ++ .../x/sys/unix/zsysnum_linux_mips64.go | 347 ++ .../x/sys/unix/zsysnum_linux_mips64le.go | 347 ++ .../x/sys/unix/zsysnum_linux_mipsle.go | 417 ++ .../x/sys/unix/zsysnum_linux_ppc64.go | 396 ++ .../x/sys/unix/zsysnum_linux_ppc64le.go | 396 ++ .../x/sys/unix/zsysnum_linux_riscv64.go | 298 ++ .../x/sys/unix/zsysnum_linux_s390x.go | 361 ++ .../x/sys/unix/zsysnum_linux_sparc64.go | 376 ++ .../x/sys/unix/zsysnum_netbsd_386.go | 274 ++ .../x/sys/unix/zsysnum_netbsd_amd64.go | 274 ++ .../x/sys/unix/zsysnum_netbsd_arm.go | 274 ++ .../x/sys/unix/zsysnum_netbsd_arm64.go | 274 ++ .../x/sys/unix/zsysnum_openbsd_386.go | 218 + .../x/sys/unix/zsysnum_openbsd_amd64.go | 218 + .../x/sys/unix/zsysnum_openbsd_arm.go | 218 + .../x/sys/unix/zsysnum_openbsd_arm64.go | 217 + .../golang.org/x/sys/unix/ztypes_aix_ppc.go | 352 ++ .../golang.org/x/sys/unix/ztypes_aix_ppc64.go | 356 ++ .../x/sys/unix/ztypes_darwin_386.go | 499 +++ .../x/sys/unix/ztypes_darwin_amd64.go | 509 +++ .../x/sys/unix/ztypes_darwin_arm.go | 500 +++ .../x/sys/unix/ztypes_darwin_arm64.go | 509 +++ .../x/sys/unix/ztypes_dragonfly_amd64.go | 469 +++ .../x/sys/unix/ztypes_freebsd_386.go | 700 ++++ .../x/sys/unix/ztypes_freebsd_amd64.go | 706 ++++ .../x/sys/unix/ztypes_freebsd_arm.go | 683 ++++ .../x/sys/unix/ztypes_freebsd_arm64.go | 684 ++++ .../golang.org/x/sys/unix/ztypes_linux_386.go | 2586 ++++++++++++ .../x/sys/unix/ztypes_linux_amd64.go | 2600 ++++++++++++ .../golang.org/x/sys/unix/ztypes_linux_arm.go | 2577 ++++++++++++ .../x/sys/unix/ztypes_linux_arm64.go | 2579 ++++++++++++ .../x/sys/unix/ztypes_linux_mips.go | 2583 ++++++++++++ .../x/sys/unix/ztypes_linux_mips64.go | 2581 ++++++++++++ .../x/sys/unix/ztypes_linux_mips64le.go | 2581 ++++++++++++ .../x/sys/unix/ztypes_linux_mipsle.go | 2583 ++++++++++++ .../x/sys/unix/ztypes_linux_ppc64.go | 2589 ++++++++++++ .../x/sys/unix/ztypes_linux_ppc64le.go | 2589 ++++++++++++ .../x/sys/unix/ztypes_linux_riscv64.go | 2607 ++++++++++++ .../x/sys/unix/ztypes_linux_s390x.go | 2603 ++++++++++++ .../x/sys/unix/ztypes_linux_sparc64.go | 2584 ++++++++++++ .../x/sys/unix/ztypes_netbsd_386.go | 466 +++ .../x/sys/unix/ztypes_netbsd_amd64.go | 473 +++ .../x/sys/unix/ztypes_netbsd_arm.go | 471 +++ .../x/sys/unix/ztypes_netbsd_arm64.go | 473 +++ .../x/sys/unix/ztypes_openbsd_386.go | 571 +++ .../x/sys/unix/ztypes_openbsd_amd64.go | 571 +++ .../x/sys/unix/ztypes_openbsd_arm.go | 572 +++ .../x/sys/unix/ztypes_openbsd_arm64.go | 565 +++ .../x/sys/unix/ztypes_solaris_amd64.go | 442 ++ vendor/google.golang.org/grpc/AUTHORS | 1 + vendor/google.golang.org/grpc/LICENSE | 202 + .../grpc/codes/code_string.go | 62 + vendor/google.golang.org/grpc/codes/codes.go | 197 + vendor/modules.txt | 93 + 915 files changed, 378049 insertions(+), 11 deletions(-) create mode 100644 address_generator.go create mode 100644 blockchain_scanner.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 keys_generator.go create mode 100644 recovery_tool.go create mode 100644 vendor/github.com/aead/siphash/.gitignore create mode 100644 vendor/github.com/aead/siphash/.travis.yml create mode 100644 vendor/github.com/aead/siphash/LICENSE create mode 100644 vendor/github.com/aead/siphash/README.md create mode 100644 vendor/github.com/aead/siphash/siphash.go create mode 100644 vendor/github.com/aead/siphash/siphash128.go create mode 100644 vendor/github.com/aead/siphash/siphash_386.go create mode 100644 vendor/github.com/aead/siphash/siphash_386.s create mode 100644 vendor/github.com/aead/siphash/siphash_amd64.go create mode 100644 vendor/github.com/aead/siphash/siphash_amd64.s create mode 100644 vendor/github.com/aead/siphash/siphash_generic.go create mode 100644 vendor/github.com/aead/siphash/siphash_ref.go create mode 100644 vendor/github.com/btcsuite/btcd/LICENSE create mode 100644 vendor/github.com/btcsuite/btcd/addrmgr/addrmanager.go create mode 100644 vendor/github.com/btcsuite/btcd/addrmgr/cov_report.sh create mode 100644 vendor/github.com/btcsuite/btcd/addrmgr/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/addrmgr/knownaddress.go create mode 100644 vendor/github.com/btcsuite/btcd/addrmgr/log.go create mode 100644 vendor/github.com/btcsuite/btcd/addrmgr/network.go create mode 100644 vendor/github.com/btcsuite/btcd/addrmgr/test_coverage.txt create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/README.md create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/accept.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/blockindex.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/chain.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/chainio.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/chainview.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/checkpoints.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/compress.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/difficulty.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/error.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/log.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/mediantime.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/merkle.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/notifications.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/process.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/scriptval.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/thresholdstate.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/timesorter.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/upgrade.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/utxoviewpoint.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/validate.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/versionbits.go create mode 100644 vendor/github.com/btcsuite/btcd/blockchain/weight.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/README.md create mode 100644 vendor/github.com/btcsuite/btcd/btcec/btcec.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/ciphering.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/field.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/genprecomps.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/gensecp256k1.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/precompute.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/privkey.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/pubkey.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/secp256k1.go create mode 100644 vendor/github.com/btcsuite/btcd/btcec/signature.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/CONTRIBUTORS create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/README.md create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/btcdextcmds.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/btcdextresults.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/btcwalletextcmds.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/chainsvrcmds.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/chainsvrresults.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/chainsvrwscmds.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/chainsvrwsntfns.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/chainsvrwsresults.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/cmdinfo.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/cmdparse.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/error.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/help.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/helpers.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/jsonrpc.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/jsonrpcerr.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/register.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/walletsvrcmds.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/walletsvrresults.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/walletsvrwscmds.go create mode 100644 vendor/github.com/btcsuite/btcd/btcjson/walletsvrwsntfns.go create mode 100644 vendor/github.com/btcsuite/btcd/chaincfg/README.md create mode 100644 vendor/github.com/btcsuite/btcd/chaincfg/chainhash/README.md create mode 100644 vendor/github.com/btcsuite/btcd/chaincfg/chainhash/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/chaincfg/chainhash/hash.go create mode 100644 vendor/github.com/btcsuite/btcd/chaincfg/chainhash/hashfuncs.go create mode 100644 vendor/github.com/btcsuite/btcd/chaincfg/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/chaincfg/genesis.go create mode 100644 vendor/github.com/btcsuite/btcd/chaincfg/params.go create mode 100644 vendor/github.com/btcsuite/btcd/connmgr/README.md create mode 100644 vendor/github.com/btcsuite/btcd/connmgr/connmanager.go create mode 100644 vendor/github.com/btcsuite/btcd/connmgr/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/connmgr/dynamicbanscore.go create mode 100644 vendor/github.com/btcsuite/btcd/connmgr/log.go create mode 100644 vendor/github.com/btcsuite/btcd/connmgr/seed.go create mode 100644 vendor/github.com/btcsuite/btcd/connmgr/tor.go create mode 100644 vendor/github.com/btcsuite/btcd/database/README.md create mode 100644 vendor/github.com/btcsuite/btcd/database/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/database/driver.go create mode 100644 vendor/github.com/btcsuite/btcd/database/error.go create mode 100644 vendor/github.com/btcsuite/btcd/database/interface.go create mode 100644 vendor/github.com/btcsuite/btcd/database/log.go create mode 100644 vendor/github.com/btcsuite/btcd/peer/README.md create mode 100644 vendor/github.com/btcsuite/btcd/peer/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/peer/log.go create mode 100644 vendor/github.com/btcsuite/btcd/peer/mruinvmap.go create mode 100644 vendor/github.com/btcsuite/btcd/peer/mrunoncemap.go create mode 100644 vendor/github.com/btcsuite/btcd/peer/peer.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/CONTRIBUTORS create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/README.md create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/chain.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/extensions.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/infrastructure.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/log.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/mining.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/net.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/notify.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/rawrequest.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/rawtransactions.go create mode 100644 vendor/github.com/btcsuite/btcd/rpcclient/wallet.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/README.md create mode 100644 vendor/github.com/btcsuite/btcd/txscript/consensus.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/engine.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/error.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/hashcache.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/log.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/opcode.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/pkscript.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/script.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/scriptbuilder.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/scriptnum.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/sigcache.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/sign.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/stack.go create mode 100644 vendor/github.com/btcsuite/btcd/txscript/standard.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/README.md create mode 100644 vendor/github.com/btcsuite/btcd/wire/blockheader.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/common.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/doc.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/error.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/invvect.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/message.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgaddr.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgalert.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgblock.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgcfcheckpt.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgcfheaders.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgcfilter.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgfeefilter.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgfilteradd.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgfilterclear.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgfilterload.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msggetaddr.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msggetblocks.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msggetcfcheckpt.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msggetcfheaders.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msggetcfilters.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msggetdata.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msggetheaders.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgheaders.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msginv.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgmempool.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgmerkleblock.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgnotfound.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgping.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgpong.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgreject.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgsendheaders.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgtx.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgverack.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/msgversion.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/netaddress.go create mode 100644 vendor/github.com/btcsuite/btcd/wire/protocol.go create mode 100644 vendor/github.com/btcsuite/btclog/.gitignore create mode 100644 vendor/github.com/btcsuite/btclog/.travis.yml create mode 100644 vendor/github.com/btcsuite/btclog/LICENSE create mode 100644 vendor/github.com/btcsuite/btclog/README.md create mode 100644 vendor/github.com/btcsuite/btclog/doc.go create mode 100644 vendor/github.com/btcsuite/btclog/goclean.sh create mode 100644 vendor/github.com/btcsuite/btclog/interface.go create mode 100644 vendor/github.com/btcsuite/btclog/log.go create mode 100644 vendor/github.com/btcsuite/btcutil/.gitignore create mode 100644 vendor/github.com/btcsuite/btcutil/.travis.yml create mode 100644 vendor/github.com/btcsuite/btcutil/LICENSE create mode 100644 vendor/github.com/btcsuite/btcutil/README.md create mode 100644 vendor/github.com/btcsuite/btcutil/address.go create mode 100644 vendor/github.com/btcsuite/btcutil/amount.go create mode 100644 vendor/github.com/btcsuite/btcutil/appdata.go create mode 100644 vendor/github.com/btcsuite/btcutil/base58/README.md create mode 100644 vendor/github.com/btcsuite/btcutil/base58/alphabet.go create mode 100644 vendor/github.com/btcsuite/btcutil/base58/base58.go create mode 100644 vendor/github.com/btcsuite/btcutil/base58/base58check.go create mode 100644 vendor/github.com/btcsuite/btcutil/base58/cov_report.sh create mode 100644 vendor/github.com/btcsuite/btcutil/base58/doc.go create mode 100644 vendor/github.com/btcsuite/btcutil/base58/genalphabet.go create mode 100644 vendor/github.com/btcsuite/btcutil/bech32/README.md create mode 100644 vendor/github.com/btcsuite/btcutil/bech32/bech32.go create mode 100644 vendor/github.com/btcsuite/btcutil/bech32/doc.go create mode 100644 vendor/github.com/btcsuite/btcutil/block.go create mode 100644 vendor/github.com/btcsuite/btcutil/certgen.go create mode 100644 vendor/github.com/btcsuite/btcutil/const.go create mode 100644 vendor/github.com/btcsuite/btcutil/cov_report.sh create mode 100644 vendor/github.com/btcsuite/btcutil/doc.go create mode 100644 vendor/github.com/btcsuite/btcutil/gcs/README.md create mode 100644 vendor/github.com/btcsuite/btcutil/gcs/builder/builder.go create mode 100644 vendor/github.com/btcsuite/btcutil/gcs/doc.go create mode 100644 vendor/github.com/btcsuite/btcutil/gcs/gcs.go create mode 100644 vendor/github.com/btcsuite/btcutil/goclean.sh create mode 100644 vendor/github.com/btcsuite/btcutil/hash160.go create mode 100644 vendor/github.com/btcsuite/btcutil/hdkeychain/README.md create mode 100644 vendor/github.com/btcsuite/btcutil/hdkeychain/cov_report.sh create mode 100644 vendor/github.com/btcsuite/btcutil/hdkeychain/doc.go create mode 100644 vendor/github.com/btcsuite/btcutil/hdkeychain/extendedkey.go create mode 100644 vendor/github.com/btcsuite/btcutil/hdkeychain/test_coverage.txt create mode 100644 vendor/github.com/btcsuite/btcutil/net.go create mode 100644 vendor/github.com/btcsuite/btcutil/net_noop.go create mode 100644 vendor/github.com/btcsuite/btcutil/test_coverage.txt create mode 100644 vendor/github.com/btcsuite/btcutil/tx.go create mode 100644 vendor/github.com/btcsuite/btcutil/wif.go create mode 100644 vendor/github.com/btcsuite/btcwallet/LICENSE create mode 100644 vendor/github.com/btcsuite/btcwallet/chain/bitcoind_client.go create mode 100644 vendor/github.com/btcsuite/btcwallet/chain/bitcoind_conn.go create mode 100644 vendor/github.com/btcsuite/btcwallet/chain/block_filterer.go create mode 100644 vendor/github.com/btcsuite/btcwallet/chain/interface.go create mode 100644 vendor/github.com/btcsuite/btcwallet/chain/log.go create mode 100644 vendor/github.com/btcsuite/btcwallet/chain/neutrino.go create mode 100644 vendor/github.com/btcsuite/btcwallet/chain/queue.go create mode 100644 vendor/github.com/btcsuite/btcwallet/chain/rpc.go create mode 100644 vendor/github.com/btcsuite/btcwallet/internal/zero/array.go create mode 100644 vendor/github.com/btcsuite/btcwallet/internal/zero/doc.go create mode 100644 vendor/github.com/btcsuite/btcwallet/internal/zero/slice.go create mode 100644 vendor/github.com/btcsuite/btcwallet/snacl/snacl.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/README.md create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/address.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/cov_report.sh create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/db.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/doc.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/error.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/log.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/manager.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/migrations.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/scoped_manager.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/sync.go create mode 100644 vendor/github.com/btcsuite/btcwallet/waddrmgr/test_coverage.txt create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/LICENSE create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/README.md create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/bdb/README.md create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/bdb/db.go create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/bdb/doc.go create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/bdb/driver.go create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/cov_report.sh create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/doc.go create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/error.go create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/go.mod create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/go.sum create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/interface.go create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/migration/log.go create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/migration/manager.go create mode 100644 vendor/github.com/btcsuite/btcwallet/walletdb/test_coverage.txt create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/LICENSE create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/README.md create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/db.go create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/doc.go create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/error.go create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/go.mod create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/go.sum create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/kahnsort.go create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/log.go create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/migrations.go create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/query.go create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/tx.go create mode 100644 vendor/github.com/btcsuite/btcwallet/wtxmgr/unconfirmed.go create mode 100644 vendor/github.com/btcsuite/go-socks/LICENSE create mode 100644 vendor/github.com/btcsuite/go-socks/socks/addr.go create mode 100644 vendor/github.com/btcsuite/go-socks/socks/conn.go create mode 100644 vendor/github.com/btcsuite/go-socks/socks/dial.go create mode 100644 vendor/github.com/btcsuite/websocket/.gitignore create mode 100644 vendor/github.com/btcsuite/websocket/.travis.yml create mode 100644 vendor/github.com/btcsuite/websocket/AUTHORS create mode 100644 vendor/github.com/btcsuite/websocket/LICENSE create mode 100644 vendor/github.com/btcsuite/websocket/README.md create mode 100644 vendor/github.com/btcsuite/websocket/client.go create mode 100644 vendor/github.com/btcsuite/websocket/conn.go create mode 100644 vendor/github.com/btcsuite/websocket/doc.go create mode 100644 vendor/github.com/btcsuite/websocket/json.go create mode 100644 vendor/github.com/btcsuite/websocket/server.go create mode 100644 vendor/github.com/btcsuite/websocket/util.go create mode 100644 vendor/github.com/coreos/bbolt/.gitignore create mode 100644 vendor/github.com/coreos/bbolt/.travis.yml create mode 100644 vendor/github.com/coreos/bbolt/LICENSE create mode 100644 vendor/github.com/coreos/bbolt/Makefile create mode 100644 vendor/github.com/coreos/bbolt/README.md create mode 100644 vendor/github.com/coreos/bbolt/bolt_386.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_amd64.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_arm.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_arm64.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_linux.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_mips64x.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_mipsx.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_openbsd.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_ppc.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_ppc64.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_ppc64le.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_riscv64.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_s390x.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_unix.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_unix_solaris.go create mode 100644 vendor/github.com/coreos/bbolt/bolt_windows.go create mode 100644 vendor/github.com/coreos/bbolt/boltsync_unix.go create mode 100644 vendor/github.com/coreos/bbolt/bucket.go create mode 100644 vendor/github.com/coreos/bbolt/cursor.go create mode 100644 vendor/github.com/coreos/bbolt/db.go create mode 100644 vendor/github.com/coreos/bbolt/doc.go create mode 100644 vendor/github.com/coreos/bbolt/errors.go create mode 100644 vendor/github.com/coreos/bbolt/freelist.go create mode 100644 vendor/github.com/coreos/bbolt/freelist_hmap.go create mode 100644 vendor/github.com/coreos/bbolt/node.go create mode 100644 vendor/github.com/coreos/bbolt/page.go create mode 100644 vendor/github.com/coreos/bbolt/tx.go create mode 100644 vendor/github.com/davecgh/go-spew/LICENSE create mode 100644 vendor/github.com/davecgh/go-spew/spew/bypass.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/bypasssafe.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/common.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/config.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/doc.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/dump.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/format.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/spew.go create mode 100644 vendor/github.com/go-errors/errors/.travis.yml create mode 100644 vendor/github.com/go-errors/errors/LICENSE.MIT create mode 100644 vendor/github.com/go-errors/errors/README.md create mode 100644 vendor/github.com/go-errors/errors/cover.out create mode 100644 vendor/github.com/go-errors/errors/error.go create mode 100644 vendor/github.com/go-errors/errors/parse_panic.go create mode 100644 vendor/github.com/go-errors/errors/stackframe.go create mode 100644 vendor/github.com/golang/protobuf/AUTHORS create mode 100644 vendor/github.com/golang/protobuf/CONTRIBUTORS create mode 100644 vendor/github.com/golang/protobuf/LICENSE create mode 100644 vendor/github.com/golang/protobuf/proto/clone.go create mode 100644 vendor/github.com/golang/protobuf/proto/decode.go create mode 100644 vendor/github.com/golang/protobuf/proto/deprecated.go create mode 100644 vendor/github.com/golang/protobuf/proto/discard.go create mode 100644 vendor/github.com/golang/protobuf/proto/encode.go create mode 100644 vendor/github.com/golang/protobuf/proto/equal.go create mode 100644 vendor/github.com/golang/protobuf/proto/extensions.go create mode 100644 vendor/github.com/golang/protobuf/proto/lib.go create mode 100644 vendor/github.com/golang/protobuf/proto/message_set.go create mode 100644 vendor/github.com/golang/protobuf/proto/pointer_reflect.go create mode 100644 vendor/github.com/golang/protobuf/proto/pointer_unsafe.go create mode 100644 vendor/github.com/golang/protobuf/proto/properties.go create mode 100644 vendor/github.com/golang/protobuf/proto/table_marshal.go create mode 100644 vendor/github.com/golang/protobuf/proto/table_merge.go create mode 100644 vendor/github.com/golang/protobuf/proto/table_unmarshal.go create mode 100644 vendor/github.com/golang/protobuf/proto/text.go create mode 100644 vendor/github.com/golang/protobuf/proto/text_parser.go create mode 100644 vendor/github.com/kkdai/bstream/.gitignore create mode 100644 vendor/github.com/kkdai/bstream/.travis.yml create mode 100644 vendor/github.com/kkdai/bstream/LICENSE create mode 100644 vendor/github.com/kkdai/bstream/README.md create mode 100644 vendor/github.com/kkdai/bstream/bstream.go create mode 100644 vendor/github.com/lightninglabs/gozmq/LICENSE create mode 100644 vendor/github.com/lightninglabs/gozmq/README.md create mode 100644 vendor/github.com/lightninglabs/gozmq/go.mod create mode 100644 vendor/github.com/lightninglabs/gozmq/zmq.go create mode 100644 vendor/github.com/lightninglabs/neutrino/.gitignore create mode 100644 vendor/github.com/lightninglabs/neutrino/.travis.yml create mode 100644 vendor/github.com/lightninglabs/neutrino/LICENSE create mode 100644 vendor/github.com/lightninglabs/neutrino/README.md create mode 100644 vendor/github.com/lightninglabs/neutrino/banman/codec.go create mode 100644 vendor/github.com/lightninglabs/neutrino/banman/reason.go create mode 100644 vendor/github.com/lightninglabs/neutrino/banman/store.go create mode 100644 vendor/github.com/lightninglabs/neutrino/banman/util.go create mode 100644 vendor/github.com/lightninglabs/neutrino/batch_spend_reporter.go create mode 100644 vendor/github.com/lightninglabs/neutrino/blockmanager.go create mode 100644 vendor/github.com/lightninglabs/neutrino/blockntfns/log.go create mode 100644 vendor/github.com/lightninglabs/neutrino/blockntfns/manager.go create mode 100644 vendor/github.com/lightninglabs/neutrino/blockntfns/notification.go create mode 100644 vendor/github.com/lightninglabs/neutrino/btcd_checkout.sh create mode 100644 vendor/github.com/lightninglabs/neutrino/cache/cache.go create mode 100644 vendor/github.com/lightninglabs/neutrino/cache/cacheable_block.go create mode 100644 vendor/github.com/lightninglabs/neutrino/cache/cacheable_filter.go create mode 100644 vendor/github.com/lightninglabs/neutrino/cache/lru/lru.go create mode 100644 vendor/github.com/lightninglabs/neutrino/chainsync/filtercontrol.go create mode 100644 vendor/github.com/lightninglabs/neutrino/errors.go create mode 100644 vendor/github.com/lightninglabs/neutrino/filterdb/db.go create mode 100644 vendor/github.com/lightninglabs/neutrino/go.mod create mode 100644 vendor/github.com/lightninglabs/neutrino/go.sum create mode 100644 vendor/github.com/lightninglabs/neutrino/gotest.sh create mode 100644 vendor/github.com/lightninglabs/neutrino/headerfs/file.go create mode 100644 vendor/github.com/lightninglabs/neutrino/headerfs/index.go create mode 100644 vendor/github.com/lightninglabs/neutrino/headerfs/store.go create mode 100644 vendor/github.com/lightninglabs/neutrino/headerfs/truncate.go create mode 100644 vendor/github.com/lightninglabs/neutrino/headerfs/truncate_windows.go create mode 100644 vendor/github.com/lightninglabs/neutrino/headerlist/bounded_header_list.go create mode 100644 vendor/github.com/lightninglabs/neutrino/headerlist/header_list.go create mode 100644 vendor/github.com/lightninglabs/neutrino/headerlogger.go create mode 100644 vendor/github.com/lightninglabs/neutrino/log.go create mode 100644 vendor/github.com/lightninglabs/neutrino/mock_store.go create mode 100644 vendor/github.com/lightninglabs/neutrino/neutrino.go create mode 100644 vendor/github.com/lightninglabs/neutrino/notifications.go create mode 100644 vendor/github.com/lightninglabs/neutrino/pushtx/broadcaster.go create mode 100644 vendor/github.com/lightninglabs/neutrino/pushtx/error.go create mode 100644 vendor/github.com/lightninglabs/neutrino/pushtx/log.go create mode 100644 vendor/github.com/lightninglabs/neutrino/query.go create mode 100644 vendor/github.com/lightninglabs/neutrino/rescan.go create mode 100644 vendor/github.com/lightninglabs/neutrino/utxoscanner.go create mode 100644 vendor/github.com/lightningnetwork/lnd/LICENSE create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/README.md create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/accept_channel.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/announcement_signatures.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/channel_announcement.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/channel_id.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/channel_reestablish.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/channel_update.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/closing_signed.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/commit_sig.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/error.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/features.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/funding_created.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/funding_locked.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/funding_signed.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/gossip_timestamp_range.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/init_message.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/lnwire.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/message.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/msat.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/netaddress.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/node_announcement.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/onion_error.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/open_channel.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/ping.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/pong.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/query_channel_range.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/query_short_chan_ids.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/reply_channel_range.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/reply_short_chan_ids_end.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/revoke_and_ack.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/short_channel_id.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/shutdown.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/signature.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/update_add_htlc.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_htlc.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/update_fail_malformed_htlc.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/update_fee.go create mode 100644 vendor/github.com/lightningnetwork/lnd/lnwire/update_fulfill_htlc.go create mode 100644 vendor/github.com/lightningnetwork/lnd/queue/LICENSE create mode 100644 vendor/github.com/lightningnetwork/lnd/queue/gc_queue.go create mode 100644 vendor/github.com/lightningnetwork/lnd/queue/go.mod create mode 100644 vendor/github.com/lightningnetwork/lnd/queue/go.sum create mode 100644 vendor/github.com/lightningnetwork/lnd/queue/queue.go create mode 100644 vendor/github.com/lightningnetwork/lnd/ticker/LICENSE create mode 100644 vendor/github.com/lightningnetwork/lnd/ticker/force.go create mode 100644 vendor/github.com/lightningnetwork/lnd/ticker/go.mod create mode 100644 vendor/github.com/lightningnetwork/lnd/ticker/ticker.go create mode 100644 vendor/github.com/lightningnetwork/lnd/tor/README.md create mode 100644 vendor/github.com/lightningnetwork/lnd/tor/controller.go create mode 100644 vendor/github.com/lightningnetwork/lnd/tor/net.go create mode 100644 vendor/github.com/lightningnetwork/lnd/tor/onionaddr.go create mode 100644 vendor/github.com/lightningnetwork/lnd/tor/tor.go create mode 100644 vendor/github.com/lightningnetwork/lnd/zpay32/README.md create mode 100644 vendor/github.com/lightningnetwork/lnd/zpay32/amountunits.go create mode 100644 vendor/github.com/lightningnetwork/lnd/zpay32/bech32.go create mode 100644 vendor/github.com/lightningnetwork/lnd/zpay32/hophint.go create mode 100644 vendor/github.com/lightningnetwork/lnd/zpay32/invoice.go create mode 100644 vendor/github.com/miekg/dns/.gitignore create mode 100644 vendor/github.com/miekg/dns/.travis.yml create mode 100644 vendor/github.com/miekg/dns/AUTHORS create mode 100644 vendor/github.com/miekg/dns/CONTRIBUTORS create mode 100644 vendor/github.com/miekg/dns/COPYRIGHT create mode 100644 vendor/github.com/miekg/dns/LICENSE create mode 100644 vendor/github.com/miekg/dns/Makefile.fuzz create mode 100644 vendor/github.com/miekg/dns/README.md create mode 100644 vendor/github.com/miekg/dns/client.go create mode 100644 vendor/github.com/miekg/dns/clientconfig.go create mode 100644 vendor/github.com/miekg/dns/compress_generate.go create mode 100644 vendor/github.com/miekg/dns/dane.go create mode 100644 vendor/github.com/miekg/dns/defaults.go create mode 100644 vendor/github.com/miekg/dns/dns.go create mode 100644 vendor/github.com/miekg/dns/dnssec.go create mode 100644 vendor/github.com/miekg/dns/dnssec_keygen.go create mode 100644 vendor/github.com/miekg/dns/dnssec_keyscan.go create mode 100644 vendor/github.com/miekg/dns/dnssec_privkey.go create mode 100644 vendor/github.com/miekg/dns/doc.go create mode 100644 vendor/github.com/miekg/dns/edns.go create mode 100644 vendor/github.com/miekg/dns/format.go create mode 100644 vendor/github.com/miekg/dns/fuzz.go create mode 100644 vendor/github.com/miekg/dns/generate.go create mode 100644 vendor/github.com/miekg/dns/internal/socket/cmsghdr.go create mode 100644 vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_32bit.go create mode 100644 vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_64bit.go create mode 100644 vendor/github.com/miekg/dns/internal/socket/cmsghdr_other.go create mode 100644 vendor/github.com/miekg/dns/internal/socket/controlmessage.go create mode 100644 vendor/github.com/miekg/dns/internal/socket/socket.go create mode 100644 vendor/github.com/miekg/dns/internal/socket/sys.go create mode 100644 vendor/github.com/miekg/dns/labels.go create mode 100644 vendor/github.com/miekg/dns/msg.go create mode 100644 vendor/github.com/miekg/dns/msg_generate.go create mode 100644 vendor/github.com/miekg/dns/msg_helpers.go create mode 100644 vendor/github.com/miekg/dns/nsecx.go create mode 100644 vendor/github.com/miekg/dns/privaterr.go create mode 100644 vendor/github.com/miekg/dns/rawmsg.go create mode 100644 vendor/github.com/miekg/dns/reverse.go create mode 100644 vendor/github.com/miekg/dns/sanitize.go create mode 100644 vendor/github.com/miekg/dns/scan.go create mode 100644 vendor/github.com/miekg/dns/scan_rr.go create mode 100644 vendor/github.com/miekg/dns/scanner.go create mode 100644 vendor/github.com/miekg/dns/server.go create mode 100644 vendor/github.com/miekg/dns/sig0.go create mode 100644 vendor/github.com/miekg/dns/singleinflight.go create mode 100644 vendor/github.com/miekg/dns/smimea.go create mode 100644 vendor/github.com/miekg/dns/tlsa.go create mode 100644 vendor/github.com/miekg/dns/tsig.go create mode 100644 vendor/github.com/miekg/dns/types.go create mode 100644 vendor/github.com/miekg/dns/types_generate.go create mode 100644 vendor/github.com/miekg/dns/udp.go create mode 100644 vendor/github.com/miekg/dns/udp_linux.go create mode 100644 vendor/github.com/miekg/dns/udp_other.go create mode 100644 vendor/github.com/miekg/dns/udp_windows.go create mode 100644 vendor/github.com/miekg/dns/update.go create mode 100644 vendor/github.com/miekg/dns/xfr.go create mode 100644 vendor/github.com/miekg/dns/zcompress.go create mode 100644 vendor/github.com/miekg/dns/zmsg.go create mode 100644 vendor/github.com/miekg/dns/ztypes.go create mode 100644 vendor/github.com/muun/libwallet/.gitignore create mode 100644 vendor/github.com/muun/libwallet/README.md create mode 100644 vendor/github.com/muun/libwallet/V1.go create mode 100644 vendor/github.com/muun/libwallet/V2.go create mode 100644 vendor/github.com/muun/libwallet/V3.go create mode 100644 vendor/github.com/muun/libwallet/address.go create mode 100644 vendor/github.com/muun/libwallet/aes.go create mode 100644 vendor/github.com/muun/libwallet/bip70.pb.go create mode 100644 vendor/github.com/muun/libwallet/bip70.proto create mode 100644 vendor/github.com/muun/libwallet/challenge_keys.go create mode 100644 vendor/github.com/muun/libwallet/challenge_public_key.go create mode 100644 vendor/github.com/muun/libwallet/derivationpath.go create mode 100644 vendor/github.com/muun/libwallet/go.mod create mode 100644 vendor/github.com/muun/libwallet/go.sum create mode 100644 vendor/github.com/muun/libwallet/hdkeycommon.go create mode 100644 vendor/github.com/muun/libwallet/hdprivatekey.go create mode 100644 vendor/github.com/muun/libwallet/hdpublickey.go create mode 100644 vendor/github.com/muun/libwallet/invoice.go create mode 100644 vendor/github.com/muun/libwallet/keycrypter.go create mode 100644 vendor/github.com/muun/libwallet/network.go create mode 100644 vendor/github.com/muun/libwallet/partiallysignedtransaction.go create mode 100644 vendor/github.com/muun/libwallet/ripemd160.go create mode 100644 vendor/github.com/muun/libwallet/scrypt.go create mode 100644 vendor/github.com/muun/libwallet/segwit.go create mode 100644 vendor/github.com/muun/libwallet/submarineSwap.go create mode 100644 vendor/github.com/pkg/errors/.gitignore create mode 100644 vendor/github.com/pkg/errors/.travis.yml create mode 100644 vendor/github.com/pkg/errors/LICENSE create mode 100644 vendor/github.com/pkg/errors/README.md create mode 100644 vendor/github.com/pkg/errors/appveyor.yml create mode 100644 vendor/github.com/pkg/errors/errors.go create mode 100644 vendor/github.com/pkg/errors/stack.go create mode 100644 vendor/golang.org/x/crypto/AUTHORS create mode 100644 vendor/golang.org/x/crypto/CONTRIBUTORS create mode 100644 vendor/golang.org/x/crypto/LICENSE create mode 100644 vendor/golang.org/x/crypto/PATENTS create mode 100644 vendor/golang.org/x/crypto/internal/subtle/aliasing.go create mode 100644 vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go create mode 100644 vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go create mode 100644 vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go create mode 100644 vendor/golang.org/x/crypto/poly1305/mac_noasm.go create mode 100644 vendor/golang.org/x/crypto/poly1305/poly1305.go create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_amd64.go create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_amd64.s create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_arm.go create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_arm.s create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_generic.go create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_noasm.go create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_s390x.go create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_s390x.s create mode 100644 vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s create mode 100644 vendor/golang.org/x/crypto/ripemd160/ripemd160.go create mode 100644 vendor/golang.org/x/crypto/ripemd160/ripemd160block.go create mode 100644 vendor/golang.org/x/crypto/salsa20/salsa/hsalsa20.go create mode 100644 vendor/golang.org/x/crypto/salsa20/salsa/salsa208.go create mode 100644 vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.go create mode 100644 vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.s create mode 100644 vendor/golang.org/x/crypto/salsa20/salsa/salsa20_noasm.go create mode 100644 vendor/golang.org/x/crypto/salsa20/salsa/salsa20_ref.go create mode 100644 vendor/golang.org/x/crypto/scrypt/scrypt.go create mode 100644 vendor/golang.org/x/net/AUTHORS create mode 100644 vendor/golang.org/x/net/CONTRIBUTORS create mode 100644 vendor/golang.org/x/net/LICENSE create mode 100644 vendor/golang.org/x/net/PATENTS create mode 100644 vendor/golang.org/x/net/internal/socks/client.go create mode 100644 vendor/golang.org/x/net/internal/socks/socks.go create mode 100644 vendor/golang.org/x/net/proxy/direct.go create mode 100644 vendor/golang.org/x/net/proxy/per_host.go create mode 100644 vendor/golang.org/x/net/proxy/proxy.go create mode 100644 vendor/golang.org/x/net/proxy/socks5.go create mode 100644 vendor/golang.org/x/sys/AUTHORS create mode 100644 vendor/golang.org/x/sys/CONTRIBUTORS create mode 100644 vendor/golang.org/x/sys/LICENSE create mode 100644 vendor/golang.org/x/sys/PATENTS create mode 100644 vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s create mode 100644 vendor/golang.org/x/sys/cpu/byteorder.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_aix_ppc64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo.c create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mipsx.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_wasm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.s create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go create mode 100644 vendor/golang.org/x/sys/unix/.gitignore create mode 100644 vendor/golang.org/x/sys/unix/README.md create mode 100644 vendor/golang.org/x/sys/unix/affinity_linux.go create mode 100644 vendor/golang.org/x/sys/unix/aliases.go create mode 100644 vendor/golang.org/x/sys/unix/asm_aix_ppc64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_mips64x.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_mipsx.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_riscv64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_s390x.s create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_386.s create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_arm.s create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_solaris_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/bluetooth_linux.go create mode 100644 vendor/golang.org/x/sys/unix/cap_freebsd.go create mode 100644 vendor/golang.org/x/sys/unix/constants.go create mode 100644 vendor/golang.org/x/sys/unix/dev_aix_ppc.go create mode 100644 vendor/golang.org/x/sys/unix/dev_aix_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/dev_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/dev_dragonfly.go create mode 100644 vendor/golang.org/x/sys/unix/dev_freebsd.go create mode 100644 vendor/golang.org/x/sys/unix/dev_linux.go create mode 100644 vendor/golang.org/x/sys/unix/dev_netbsd.go create mode 100644 vendor/golang.org/x/sys/unix/dev_openbsd.go create mode 100644 vendor/golang.org/x/sys/unix/dirent.go create mode 100644 vendor/golang.org/x/sys/unix/endian_big.go create mode 100644 vendor/golang.org/x/sys/unix/endian_little.go create mode 100644 vendor/golang.org/x/sys/unix/env_unix.go create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/fcntl.go create mode 100644 vendor/golang.org/x/sys/unix/fcntl_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go create mode 100644 vendor/golang.org/x/sys/unix/gccgo.go create mode 100644 vendor/golang.org/x/sys/unix/gccgo_c.c create mode 100644 vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ioctl.go create mode 100644 vendor/golang.org/x/sys/unix/mkall.sh create mode 100644 vendor/golang.org/x/sys/unix/mkasm_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/mkerrors.sh create mode 100644 vendor/golang.org/x/sys/unix/mkpost.go create mode 100644 vendor/golang.org/x/sys/unix/mksyscall.go create mode 100644 vendor/golang.org/x/sys/unix/mksyscall_aix_ppc.go create mode 100644 vendor/golang.org/x/sys/unix/mksyscall_aix_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/mksyscall_solaris.go create mode 100644 vendor/golang.org/x/sys/unix/mksysctl_openbsd.go create mode 100644 vendor/golang.org/x/sys/unix/mksysnum.go create mode 100644 vendor/golang.org/x/sys/unix/pagesize_unix.go create mode 100644 vendor/golang.org/x/sys/unix/pledge_openbsd.go create mode 100644 vendor/golang.org/x/sys/unix/race.go create mode 100644 vendor/golang.org/x/sys/unix/race0.go create mode 100644 vendor/golang.org/x/sys/unix/readdirent_getdents.go create mode 100644 vendor/golang.org/x/sys/unix/readdirent_getdirentries.go create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_linux.go create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_unix.go create mode 100644 vendor/golang.org/x/sys/unix/str.go create mode 100644 vendor/golang.org/x/sys/unix/syscall.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_aix.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_aix_ppc.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_bsd.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_dragonfly.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gc.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix_gc.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go create mode 100644 vendor/golang.org/x/sys/unix/timestruct.go create mode 100644 vendor/golang.org/x/sys/unix/types_aix.go create mode 100644 vendor/golang.org/x/sys/unix/types_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/types_dragonfly.go create mode 100644 vendor/golang.org/x/sys/unix/types_freebsd.go create mode 100644 vendor/golang.org/x/sys/unix/types_netbsd.go create mode 100644 vendor/golang.org/x/sys/unix/types_openbsd.go create mode 100644 vendor/golang.org/x/sys/unix/types_solaris.go create mode 100644 vendor/golang.org/x/sys/unix/unveil_openbsd.go create mode 100644 vendor/golang.org/x/sys/unix/xattr_bsd.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_aix_ppc.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zptrace386_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zptracearm_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zptracemips_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zptracemipsle_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_11.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_11.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_11.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_11.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_aix_ppc.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_aix_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go create mode 100644 vendor/google.golang.org/grpc/AUTHORS create mode 100644 vendor/google.golang.org/grpc/LICENSE create mode 100644 vendor/google.golang.org/grpc/codes/code_string.go create mode 100644 vendor/google.golang.org/grpc/codes/codes.go create mode 100644 vendor/modules.txt diff --git a/.gitignore b/.gitignore index f1c181e..4699e3a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,2 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib +.data -# Test binary, build with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out diff --git a/address_generator.go b/address_generator.go new file mode 100644 index 0000000..0fed5a9 --- /dev/null +++ b/address_generator.go @@ -0,0 +1,103 @@ +package main + +import ( + "fmt" + "log" + + "github.com/muun/libwallet" +) + +type signingDetails struct { + RedeemScript []byte + Address libwallet.MuunAddress +} + +type AddressGenerator struct { + addrs map[string]signingDetails + userKey *libwallet.HDPrivateKey + muunKey *libwallet.HDPrivateKey +} + +func NewAddressGenerator(userKey, muunKey *libwallet.HDPrivateKey) *AddressGenerator { + return &AddressGenerator{ + addrs: make(map[string]signingDetails), + userKey: userKey, + muunKey: muunKey, + } +} + +func (g *AddressGenerator) Addresses() map[string]signingDetails { + return g.addrs +} + +func (g *AddressGenerator) Generate() { + g.generateChangeAddrs() + g.generateExternalAddrs() + g.generateContactAddrs(100) +} + +func (g *AddressGenerator) generateChangeAddrs() { + const changePath = "m/1'/1'/0" + changeUserKey, _ := g.userKey.DeriveTo(changePath) + changeMuunKey, _ := g.muunKey.DeriveTo(changePath) + + g.deriveTree(changeUserKey, changeMuunKey, 2000, "change") +} + +func (g *AddressGenerator) generateExternalAddrs() { + const externalPath = "m/1'/1'/1" + externalUserKey, _ := g.userKey.DeriveTo(externalPath) + externalMuunKey, _ := g.muunKey.DeriveTo(externalPath) + + g.deriveTree(externalUserKey, externalMuunKey, 2000, "external") +} + +func (g *AddressGenerator) generateContactAddrs(numContacts int64) { + const addressPath = "m/1'/1'/2" + contactUserKey, _ := g.userKey.DeriveTo(addressPath) + contactMuunKey, _ := g.muunKey.DeriveTo(addressPath) + for i := int64(0); i <= numContacts; i++ { + partialContactUserKey, _ := contactUserKey.DerivedAt(i, false) + partialMuunUserKey, _ := contactMuunKey.DerivedAt(i, false) + + branch := fmt.Sprintf("contacts-%v", i) + g.deriveTree(partialContactUserKey, partialMuunUserKey, 200, branch) + } +} + +func (g *AddressGenerator) deriveTree(rootUserKey, rootMuunKey *libwallet.HDPrivateKey, count int64, name string) { + + for i := int64(0); i <= count; i++ { + userKey, err := rootUserKey.DerivedAt(i, false) + if err != nil { + log.Printf("skipping child %v for %v due to %v", i, name, err) + continue + } + muunKey, err := rootMuunKey.DerivedAt(i, false) + if err != nil { + log.Printf("skipping child %v for %v due to %v", i, name, err) + continue + } + + addrV2, err := libwallet.CreateAddressV2(userKey.PublicKey(), muunKey.PublicKey()) + if err == nil { + g.addrs[addrV2.Address()] = signingDetails{ + RedeemScript: addrV2.(libwallet.RedeemableAddress).RedeemScript(), + Address: addrV2, + } + } else { + log.Printf("failed to generate %v v2 for %v due to %v", name, i, err) + } + + addrV3, err := libwallet.CreateAddressV3(userKey.PublicKey(), muunKey.PublicKey()) + if err == nil { + g.addrs[addrV3.Address()] = signingDetails{ + RedeemScript: addrV3.(libwallet.RedeemableAddress).RedeemScript(), + Address: addrV3, + } + } else { + log.Printf("failed to generate %v v3 for %v due to %v", name, i, err) + } + + } +} \ No newline at end of file diff --git a/blockchain_scanner.go b/blockchain_scanner.go new file mode 100644 index 0000000..27a061b --- /dev/null +++ b/blockchain_scanner.go @@ -0,0 +1,277 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "time" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/txscript" + + "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/wire" + + "github.com/btcsuite/btclog" + + "github.com/btcsuite/btcd/rpcclient" + + "github.com/btcsuite/btcutil" + + _ "github.com/btcsuite/btcwallet/chain" + "github.com/btcsuite/btcwallet/walletdb" + _ "github.com/btcsuite/btcwallet/walletdb/bdb" + + "github.com/btcsuite/btcd/chaincfg" + + "github.com/lightninglabs/neutrino" + "github.com/lightninglabs/neutrino/headerfs" +) + +// RelevantTx contains a PKScipt, an Address an a boolean to check if its spent or not +type RelevantTx struct { + PkScript []byte + Address string + Spent bool + Satoshis int64 + SigningDetails signingDetails + Outpoint wire.OutPoint +} + +func (tx *RelevantTx) String() string { + return fmt.Sprintf("outpoint %v:%v for %v sats on path %v", + tx.Outpoint.Hash, tx.Outpoint.Index, tx.Satoshis, tx.SigningDetails.Address.DerivationPath()) +} + +var ( + chainParams = chaincfg.MainNetParams + bitcoinGenesisDate = chainParams.GenesisBlock.Header.Timestamp +) + +var relevantTxs = make(map[wire.OutPoint]*RelevantTx) +var rescan *neutrino.Rescan + +// TODO: Add signing details to the watchAddresses map +var watchAddresses = make(map[string]signingDetails) + +func startRescan(chainService *neutrino.ChainService, addrs map[string]signingDetails, birthday int) []*RelevantTx { + watchAddresses = addrs + + // Wait till we know where the tip is + for !chainService.IsCurrent() { + } + bestBlock, _ := chainService.BestBlock() + + startHeight := findStartHeight(birthday, chainService) + fmt.Println() + fmt.Printf("Starting at height %v", startHeight.Height) + fmt.Println() + + ntfn := rpcclient.NotificationHandlers{ + OnBlockConnected: func(hash *chainhash.Hash, height int32, t time.Time) { + totalDif := bestBlock.Height - startHeight.Height + currentDif := height - startHeight.Height + progress := (float64(currentDif) / float64(totalDif)) * 100.0 + progressBar := "" + numberOfBars := int(progress / 5) + for index := 0; index <= 20; index++ { + if index <= numberOfBars { + progressBar += "■" + } else { + progressBar += "□" + } + } + + fmt.Printf("\rProgress: [%v] %.2f%%. Scanning block %v of %v.", progressBar, progress, currentDif, totalDif) + }, + OnRedeemingTx: func(tx *btcutil.Tx, details *btcjson.BlockDetails) { + for _, input := range tx.MsgTx().TxIn { + outpoint := input.PreviousOutPoint + if _, ok := relevantTxs[outpoint]; ok { + relevantTxs[outpoint].Spent = true + } + } + }, + OnRecvTx: func(tx *btcutil.Tx, details *btcjson.BlockDetails) { + checkOutpoints(tx, details.Height) + }, + } + + rescan = neutrino.NewRescan( + &neutrino.RescanChainSource{ + ChainService: chainService, + }, + neutrino.WatchAddrs(buildAddresses()...), + neutrino.NotificationHandlers(ntfn), + neutrino.StartBlock(startHeight), + neutrino.EndBlock(bestBlock), + ) + errorChan := rescan.Start() + rescan.WaitForShutdown() + if err := <-errorChan; err != nil { + panic(err) + } + + return buildUtxos() +} + +func startChainService() (*neutrino.ChainService, func(), error) { + setUpLogger() + + dir := os.TempDir() + dirFolder := filepath.Join(dir, "muunRecoveryTool") + os.RemoveAll(dirFolder) + os.MkdirAll(dirFolder, 0700) + dbPath := filepath.Join(dirFolder, "neutrino.db") + + db, err := walletdb.Open("bdb", dbPath) + if err == walletdb.ErrDbDoesNotExist { + db, err = walletdb.Create("bdb", dbPath) + if err != nil { + panic(err) + } + } + + peers := make([]string, 1) + peers[0] = "btcd-mainnet.lightning.computer" + chainService, err := neutrino.NewChainService(neutrino.Config{ + DataDir: dirFolder, + Database: db, + ChainParams: chainParams, + ConnectPeers: peers, + AddPeers: peers, + }) + if err != nil { + panic(err) + } + + err = chainService.Start() + if err != nil { + panic(err) + } + + close := func() { + db.Close() + err := chainService.Stop() + if err != nil { + panic(err) + } + os.Remove(dbPath) + os.RemoveAll(dirFolder) + } + return chainService, close, err +} + +func findStartHeight(birthday int, chain *neutrino.ChainService) *headerfs.BlockStamp { + if birthday == 0 { + return &headerfs.BlockStamp{} + } + + const ( + // birthdayBlockDelta is the maximum time delta allowed between our + // birthday timestamp and our birthday block's timestamp when searching + // for a better birthday block candidate (if possible). + birthdayBlockDelta = 2 * time.Hour + ) + + birthtime := bitcoinGenesisDate.Add(time.Duration(birthday-2) * 24 * time.Hour) + + block, _ := chain.BestBlock() + + startHeight := int32(0) + bestHeight := block.Height + + left, right := startHeight, bestHeight + + for { + mid := left + (right-left)/2 + hash, _ := chain.GetBlockHash(int64(mid)) + header, _ := chain.GetBlockHeader(hash) + + // If the search happened to reach either of our range extremes, + // then we'll just use that as there's nothing left to search. + if mid == startHeight || mid == bestHeight || mid == left { + return &headerfs.BlockStamp{ + Hash: *hash, + Height: mid, + Timestamp: header.Timestamp, + } + } + + // The block's timestamp is more than 2 hours after the + // birthday, so look for a lower block. + if header.Timestamp.Sub(birthtime) > birthdayBlockDelta { + right = mid + continue + } + + // The birthday is more than 2 hours before the block's + // timestamp, so look for a higher block. + if header.Timestamp.Sub(birthtime) < -birthdayBlockDelta { + left = mid + continue + } + + return &headerfs.BlockStamp{ + Hash: *hash, + Height: mid, + Timestamp: header.Timestamp, + } + } +} + +func checkOutpoints(tx *btcutil.Tx, height int32) { + // Loop in the output addresses + for index, output := range tx.MsgTx().TxOut { + _, addrs, _, _ := txscript.ExtractPkScriptAddrs(output.PkScript, &chainParams) + for _, addr := range addrs { + // If one of the output addresses is in our Watch Addresses map, we try to add it to our relevant tx model + if _, ok := watchAddresses[addr.EncodeAddress()]; ok { + hash := tx.Hash() + relevantTx := &RelevantTx{ + PkScript: output.PkScript, + Address: addr.String(), + Spent: false, + Satoshis: output.Value, + SigningDetails: watchAddresses[addr.EncodeAddress()], + Outpoint: wire.OutPoint{*hash, uint32(index)}, + } + + if _, ok := relevantTxs[relevantTx.Outpoint]; ok { + // If its already there we dont need to do anything + return + } + + relevantTxs[relevantTx.Outpoint] = relevantTx + } + } + } +} + +func buildUtxos() []*RelevantTx { + var utxos []*RelevantTx + for _, output := range relevantTxs { + if !output.Spent { + utxos = append(utxos, output) + } + } + return utxos +} + +func buildAddresses() []btcutil.Address { + addresses := make([]btcutil.Address, 0, len(watchAddresses)) + for addr := range watchAddresses { + address, err := btcutil.DecodeAddress(addr, &chainParams) + if err != nil { + panic(err) + } + addresses = append(addresses, address) + } + return addresses +} + +func setUpLogger() { + logger := btclog.NewBackend(os.Stdout).Logger("MUUN") + logger.SetLevel(btclog.LevelOff) + neutrino.UseLogger(logger) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c87696c --- /dev/null +++ b/go.mod @@ -0,0 +1,15 @@ +module recovery_tool + +go 1.12 + +require ( + github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 + github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f + github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d + github.com/btcsuite/btcwallet v0.0.0-20190911065739-d5cdeb4b91b0 + github.com/btcsuite/btcwallet/walletdb v1.0.0 + github.com/lightninglabs/neutrino v0.0.0-20190910092203-46d9c1c55f44 + github.com/muun/libwallet v0.1.2 +) + +replace github.com/lightninglabs/neutrino => github.com/muun/neutrino v0.0.0-20190914162326-7082af0fa257 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7c3b684 --- /dev/null +++ b/go.sum @@ -0,0 +1,221 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +git.schwanenlied.me/yawning/bsaes.git v0.0.0-20180720073208-c0276d75487e/go.mod h1:BWqTsj8PgcPriQJGl7el20J/7TuT1d/hSyFDXMEpoEo= +github.com/NebulousLabs/fastrand v0.0.0-20180208210444-3cf7173006a0/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ= +github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82/go.mod h1:GbuBk21JqF+driLX3XtJYNZjGa45YDoa9IqCTzNSfEc= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk= +github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= +github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/btcsuite/btcd v0.0.0-20180823030728-d81d8877b8f3/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/btcsuite/btcd v0.0.0-20181130015935-7d2daa5bfef2/go.mod h1:Jr9bmNVGZ7TH2Ux1QuP0ec+yGgh0gE9FIlkzQiI5bR0= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 h1:A/EVblehb75cUgXA5njHPn0kLAsykn6mJGz7rnmW5W0= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcwallet v0.0.0-20180904010540-284e2e0e696e33d5be388f7f3d9a26db703e0c06/go.mod h1:/d7QHZsfUAruXuBhyPITqoYOmJ+nq35qPsJjz/aSpCg= +github.com/btcsuite/btcwallet v0.0.0-20190313032608-acf3b04b0273/go.mod h1:mkOYY8/psBiL5E+Wb0V7M0o+N7NXi2SZJz6+RKkncIc= +github.com/btcsuite/btcwallet v0.0.0-20190319010515-89ab2044f962/go.mod h1:qMi4jGpAO6YRsd81RYDG7o5pBIGqN9faCioJdagLu64= +github.com/btcsuite/btcwallet v0.0.0-20190712034938-7a3a3e82cbb6/go.mod h1:sXVxjjP5YeWqWsiQbQDXvAw6J6Qvr8swu7MONoNaF9k= +github.com/btcsuite/btcwallet v0.0.0-20190911065739-d5cdeb4b91b0 h1:S9+cnZ7N4EvkkOBQ3lUy4p7+XjW4GS81R4QjwuT06Cw= +github.com/btcsuite/btcwallet v0.0.0-20190911065739-d5cdeb4b91b0/go.mod h1:ntLqUbZ12G8FmPX1nJj7W83WiAFOLRGiuarH4zDYdlI= +github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 h1:KGHMW5sd7yDdDMkCZ/JpP0KltolFsQcB973brBnfj4c= +github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU= +github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 h1:2VsfS0sBedcM5KmDzRMT3+b6xobqWveZGvjb+jFez5w= +github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZwEiu3jNAtfXj2n2+c8RWiE/WNA= +github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0 h1:6DxkcoMnCPY4E9cUDPB5tbuuf40SmmMkSQkoE8vCT+s= +github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= +github.com/btcsuite/btcwallet/walletdb v1.0.0 h1:mheT7vCWK5EP6rZzhxsQ7ms9+yX4VE8bwiJctECBeNw= +github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk= +github.com/btcsuite/btcwallet/wtxmgr v1.0.0 h1:aIHgViEmZmZfe0tQQqF1xyd2qBqFWxX5vZXkkbjtbeA= +github.com/btcsuite/btcwallet/wtxmgr v1.0.0/go.mod h1:vc4gBprll6BP0UJ+AIGDaySoc7MdAmZf8kelfNb8CFY= +github.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:QcFA8DZHtuIAdYKCq/BzELOaznRsCvwf4zTPmaYwaig= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v0.0.0-20180223184059-7ee3ded59d4835e10f3e7d0f7603c42aa5e83820/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v0.0.0-20180821051752-b27b920f9e71/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v0.0.0-20170724004829-f2862b476edc/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/juju/clock v0.0.0-20180808021310-bab88fc67299/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= +github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk= +github.com/juju/version v0.0.0-20180108022336-b64dbd566305/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec h1:n1NeQ3SgUHyISrjFFoO5dR748Is8dBL9qpaTNfphQrs= +github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lightninglabs/gozmq v0.0.0-20180324010646-462a8a753885/go.mod h1:KUh15naRlx/TmUMFS/p4JJrCrE6F7RGF7rsnvuu45E4= +github.com/lightninglabs/gozmq v0.0.0-20190710231225-cea2a031735d h1:tt8hwvxl6fksSfchjBGaWu+pnWJQfG1OWiCM20qOSAE= +github.com/lightninglabs/gozmq v0.0.0-20190710231225-cea2a031735d/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= +github.com/lightninglabs/neutrino v0.0.0-20181017011010-4d6069299130/go.mod h1:KJq43Fu9ceitbJsSXMILcT4mGDNI/crKmPIkDOZXFyM= +github.com/lightninglabs/neutrino v0.0.0-20190213031021-ae4583a89cfb/go.mod h1:g6cMQd+hfAU8pQTJAdjm6/EQREhupyd22f+CL0qYFOE= +github.com/lightninglabs/neutrino v0.0.0-20190313035638-e1ad4c33fb18/go.mod h1:v6tz6jbuAubTrRpX8ke2KH9sJxml8KlPQTKgo9mAp1Q= +github.com/lightninglabs/neutrino v0.0.0-20190725230401-ddf667a8b5c4/go.mod h1:vzLU75ll8qbRJIzW5dvK/UXtR9c2FecJ6VNOM8chyVM= +github.com/lightninglabs/neutrino v0.0.0-20190906012717-f087198de655/go.mod h1:awTrhbCWjWNH4yVwZ4IE7nZbvpQ27e7OyD+jao7wRxA= +github.com/lightninglabs/neutrino v0.0.0-20190910092203-46d9c1c55f44 h1:/LCNh3QEflF49ZYjfHO8yNhtQ/U/crV5Ktj5YIIrPEA= +github.com/lightninglabs/neutrino v0.0.0-20190910092203-46d9c1c55f44/go.mod h1:awTrhbCWjWNH4yVwZ4IE7nZbvpQ27e7OyD+jao7wRxA= +github.com/lightningnetwork/lightning-onion v0.0.0-20190703000913-ecc936dc56c9/go.mod h1:Sooe/CoCqa85JxqHV+IBR2HW+6t2Cv+36awSmoccswM= +github.com/lightningnetwork/lnd v0.7.1-beta-rc2 h1:N0AuHo4wI6TogabvOfpwg1LkR3RxGCvqYq0Wb7GL+ck= +github.com/lightningnetwork/lnd v0.7.1-beta-rc2/go.mod h1:ODASBFcJwVlb4aqO3m090whpP2kfA9zEvmG/pj+fOfg= +github.com/lightningnetwork/lnd/queue v1.0.1 h1:jzJKcTy3Nj5lQrooJ3aaw9Lau3I0IwvQR5sqtjdv2R0= +github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms= +github.com/lightningnetwork/lnd/ticker v1.0.0 h1:S1b60TEGoTtCe2A0yeB+ecoj/kkS4qpwh6l+AkQEZwU= +github.com/lightningnetwork/lnd/ticker v1.0.0/go.mod h1:iaLXJiVgI1sPANIF2qYYUJXjoksPNvGNYowB8aRbpX0= +github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY= +github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8 h1:PRMAcldsl4mXKJeRNB/KVNz6TlbS6hk2Rs42PqgU3Ws= +github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/muun/libwallet v0.1.2 h1:SL19DYwRYuZ09XKcnIwYSxmFMHtMde8G5AV8LAq9rXg= +github.com/muun/libwallet v0.1.2/go.mod h1:/ub+7bo/snLSWuwBXdpGDiY5HBuVsduYrUAW4yZ88Xc= +github.com/muun/neutrino v0.0.0-20190914162326-7082af0fa257 h1:NW17wq2gZlEFeW3/Zx3wSmqlD0wKGf7YvhpP+CNCsbE= +github.com/muun/neutrino v0.0.0-20190914162326-7082af0fa257/go.mod h1:awTrhbCWjWNH4yVwZ4IE7nZbvpQ27e7OyD+jao7wRxA= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY= +github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +go.etcd.io/bbolt v1.3.0/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180821023952-922f4815f713/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180821140842-3b58ed4ad339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA= +google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA= +gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/keys_generator.go b/keys_generator.go new file mode 100644 index 0000000..dcba06d --- /dev/null +++ b/keys_generator.go @@ -0,0 +1,31 @@ +package main + +import ( + log "log" + + "github.com/btcsuite/btcutil/base58" + "github.com/muun/libwallet" +) + +func buildExtendedKey(rawKey, recoveryCode string) *libwallet.DecryptedPrivateKey { + recoveryCodeBytes := extractBytes(recoveryCode) + salt := extractSalt(rawKey) + + privKey := libwallet.NewChallengePrivateKey(recoveryCodeBytes, salt) + + key, err := privKey.DecryptKey(rawKey, libwallet.Mainnet()) + if err != nil { + log.Fatalf("failed to decrypt key: %v", err) + } + + return key +} + +func extractSalt(rawKey string) []byte { + bytes := base58.Decode(rawKey) + return bytes[len(bytes)-8:] +} + +func extractBytes(recoveryCode string) []byte { + return []byte(recoveryCode) +} diff --git a/recovery_tool.go b/recovery_tool.go new file mode 100644 index 0000000..0955cf1 --- /dev/null +++ b/recovery_tool.go @@ -0,0 +1,347 @@ +package main + +import ( + "bytes" + "encoding/hex" + "fmt" + "log" + "os" + "strconv" + "strings" + + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" + + "github.com/muun/libwallet" +) + +func main() { + chainService, close, _ := startChainService() + defer close() + + printWelcomeMessage() + + recoveryCode := readRecoveryCode() + + userRawKey := readKey("first encrypted private key", 147) + userKey := buildExtendedKey(userRawKey, recoveryCode) + userKey.Key.Path = "m/1'/1'" + + muunRawKey := readKey("second encrypted private key", 147) + muunKey := buildExtendedKey(muunRawKey, recoveryCode) + derivedMuunKey, err := muunKey.Key.DeriveTo("m/1'/1'") + if err != nil { + printError(err) + } + + sweepAddress := readSweepAddress() + + fmt.Println("") + fmt.Println("Starting to scan the blockchain. This may take a while.") + + g := NewAddressGenerator(userKey.Key, muunKey.Key) + g.Generate() + + birthday := muunKey.Birthday + if birthday == 0xFFFF { + birthday = 0 + } + + utxos := startRescan(chainService, g.Addresses(), birthday) + fmt.Println("") + + if len(utxos) > 0 { + fmt.Printf("The recovery tool has found the following utxos: %v", utxos) + } else { + fmt.Printf("No utxos found") + fmt.Println() + return + } + fmt.Println() + + // This is fun: + // First we build a sweep tx with 0 fee with the only purpouse of seeing its signed size + zeroFeehexSweepTx := buildSweepTx(utxos, sweepAddress, 0) + zeroFeeSweepTx, err := buildSignedTx(utxos, zeroFeehexSweepTx, userKey.Key, derivedMuunKey) + if err != nil { + printError(err) + } + weightInBytes := int64(zeroFeeSweepTx.SerializeSize()) + fee := readFee(zeroFeeSweepTx.TxOut[0].Value, weightInBytes) + // Then we re-build the sweep tx with the actual fee + hexSweepTx := buildSweepTx(utxos, sweepAddress, fee) + tx, err := buildSignedTx(utxos, hexSweepTx, userKey.Key, derivedMuunKey) + if err != nil { + printError(err) + } + fmt.Println("Transaction ready to be sent") + + err = chainService.SendTransaction(tx) + if err != nil { + printError(err) + } + + fmt.Printf("Transaction sent! You can check the status here: https://blockstream.info/tx/%v", tx.TxHash().String()) + fmt.Println("") + fmt.Printf("If you have any feedback, feel free to share it with us. Our email is contact@muun.com") + fmt.Println("") + +} + +func buildSweepTx(utxos []*RelevantTx, sweepAddress btcutil.Address, fee int64) string { + + tx := wire.NewMsgTx(2) + value := int64(0) + + for _, utxo := range utxos { + tx.AddTxIn(wire.NewTxIn(&utxo.Outpoint, []byte{}, [][]byte{})) + value += utxo.Satoshis + } + + fmt.Println() + fmt.Printf("Total balance in satoshis: %v", value) + fmt.Println() + + value -= fee + + script, err := txscript.PayToAddrScript(sweepAddress) + if err != nil { + printError(err) + } + tx.AddTxOut(wire.NewTxOut(value, script)) + + writer := &bytes.Buffer{} + err = tx.Serialize(writer) + if err != nil { + panic(err) + } + + if fee != 0 { + readConfirmation(value, fee, sweepAddress.String()) + } + + return hex.EncodeToString(writer.Bytes()) +} + +func buildSignedTx(utxos []*RelevantTx, hexSweepTx string, userKey *libwallet.HDPrivateKey, + muunKey *libwallet.HDPrivateKey) (*wire.MsgTx, error) { + + pstx, err := libwallet.NewPartiallySignedTransaction(hexSweepTx) + if err != nil { + printError(err) + } + + for index, utxo := range utxos { + input := &input{ + utxo, + []byte{}, + } + + pstx.AddInput(input) + sig, err := pstx.MuunSignatureForInput(index, userKey.PublicKey(), muunKey) + if err != nil { + panic(err) + } + input.muunSignature = sig + } + + signedTx, err := pstx.Sign(userKey, muunKey.PublicKey()) + if err != nil { + return nil, err + } + + wireTx := wire.NewMsgTx(0) + wireTx.BtcDecode(bytes.NewReader(signedTx.Bytes), 0, wire.WitnessEncoding) + return wireTx, nil +} + +func printError(err error) { + log.Printf("The recovery tool failed with the following error: %v", err.Error()) + log.Printf("") + log.Printf("You can try again or contact us at support@muun.com") + panic(err) +} + +func printWelcomeMessage() { + fmt.Println("Welcome to Muun's Recovery Tool") + fmt.Println("") + fmt.Println("You can use this tool to swipe all the balance in your muun account to an") + fmt.Println("address of your choosing.") + fmt.Println("") + fmt.Println("To do this you will need:") + fmt.Println("* The recovery code, that you set up when you created your muun account") + fmt.Println("* The two encrypted private keys that you exported from your muun wallet") + fmt.Println("* A destination bitcoin address where all your funds will be sent") + fmt.Println("") + fmt.Println("If you have any questions, contact us at contact@muun.com") + fmt.Println("") +} + +func readRecoveryCode() string { + fmt.Println("") + fmt.Printf("Enter your Recovery Code") + fmt.Println() + fmt.Println("(it looks like this: 'ABCD-1234-POW2-R561-P120-JK26-12RW-45TT')") + fmt.Print("> ") + var userInput string + fmt.Scan(&userInput) + userInput = strings.TrimSpace(userInput) + + finalRC := strings.ToUpper(userInput) + + if strings.Count(finalRC, "-") != 7 { + fmt.Printf("Wrong recovery code, remember to add the '-' separator between the 4 characters chunks") + fmt.Println() + fmt.Println("Please, try again") + + return readRecoveryCode() + } + + if len(finalRC) != 39 { + fmt.Println("Your recovery code must have 39 characters") + fmt.Println("Please, try again") + + return readRecoveryCode() + } + + return finalRC +} + +func readKey(keyType string, characters int) string { + fmt.Println("") + fmt.Printf("Enter your %v", keyType) + fmt.Println() + fmt.Println("(it looks like this: '9xzpc7y6sNtRvh8Fh...')") + fmt.Print("> ") + var userInput string + fmt.Scan(&userInput) + userInput = strings.TrimSpace(userInput) + + if len(userInput) != characters { + fmt.Printf("Your %v must have %v characters", keyType, characters) + fmt.Println("") + fmt.Println("Please, try again") + + return readKey(keyType, characters) + } + + return userInput +} + +func readSweepAddress() btcutil.Address { + fmt.Println("") + fmt.Println("Enter your destination bitcoin address") + fmt.Print("> ") + var userInput string + fmt.Scan(&userInput) + userInput = strings.TrimSpace(userInput) + + addr, err := btcutil.DecodeAddress(userInput, &chainParams) + if err != nil { + fmt.Println("This is not a valid bitcoin address") + fmt.Println("") + fmt.Println("Please, try again") + + return readSweepAddress() + } + + return addr +} + +func readFee(totalBalance, weight int64) int64 { + fmt.Println("") + fmt.Printf("Enter the fee in satoshis per byte. Tx weight: %v bytes. You can check the status of the mempool here: https://bitcoinfees.earn.com/#fees", weight) + fmt.Println() + fmt.Println("(Example: 5)") + fmt.Print("> ") + var userInput string + fmt.Scan(&userInput) + feeInSatsPerByte, err := strconv.ParseInt(userInput, 10, 64) + if err != nil || feeInSatsPerByte <= 0 { + fmt.Printf("The fee must be a number") + fmt.Println("") + fmt.Println("Please, try again") + + return readFee(totalBalance, weight) + } + + totalFee := feeInSatsPerByte * weight + + if totalBalance-totalFee < 546 { + fmt.Printf("The fee is too high. The amount left must be higher than dust") + fmt.Println("") + fmt.Println("Please, try again") + + return readFee(totalBalance, weight) + } + + return totalFee +} + +func readConfirmation(value, fee int64, address string) { + fmt.Println("") + fmt.Printf("About to send %v satoshis with fee: %v satoshis to %v", value, fee, address) + fmt.Println() + fmt.Println("Confirm? (y/n)") + fmt.Print("> ") + var userInput string + fmt.Scan(&userInput) + + if userInput == "y" || userInput == "Y" { + return + } + + if userInput == "n" || userInput == "N" { + log.Println() + log.Printf("Recovery tool stopped") + log.Println() + log.Printf("You can try again or contact us at support@muun.com") + os.Exit(1) + } + + fmt.Println() + fmt.Println("You can only enter 'y' to accept or 'n' to cancel") + readConfirmation(value, fee, address) +} + +type input struct { + tx *RelevantTx + muunSignature []byte +} + +func (i *input) OutPoint() libwallet.Outpoint { + return &outpoint{tx: i.tx} +} + +func (i *input) Address() libwallet.MuunAddress { + return i.tx.SigningDetails.Address +} + +func (i *input) UserSignature() []byte { + return []byte{} +} + +func (i *input) MuunSignature() []byte { + return i.muunSignature +} + +func (i *input) SubmarineSwap() libwallet.InputSubmarineSwap { + return nil +} + +type outpoint struct { + tx *RelevantTx +} + +func (o *outpoint) TxId() []byte { + return o.tx.Outpoint.Hash.CloneBytes() +} + +func (o *outpoint) Index() int { + return int(o.tx.Outpoint.Index) +} + +func (o *outpoint) Amount() int64 { + return o.tx.Satoshis +} diff --git a/vendor/github.com/aead/siphash/.gitignore b/vendor/github.com/aead/siphash/.gitignore new file mode 100644 index 0000000..9d3d843 --- /dev/null +++ b/vendor/github.com/aead/siphash/.gitignore @@ -0,0 +1,25 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test +.vscode + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/aead/siphash/.travis.yml b/vendor/github.com/aead/siphash/.travis.yml new file mode 100644 index 0000000..4576e93 --- /dev/null +++ b/vendor/github.com/aead/siphash/.travis.yml @@ -0,0 +1,15 @@ +language: go + +go: + - "1.6.x" + - "1.7.x" + - "1.8.x" + - "1.9.x" + - "1.10.x" + +env: + - TRAVIS_GOARCH=amd64 + - TRAVIS_GOARCH=386 + +before_install: + - export GOARCH=$TRAVIS_GOARCH \ No newline at end of file diff --git a/vendor/github.com/aead/siphash/LICENSE b/vendor/github.com/aead/siphash/LICENSE new file mode 100644 index 0000000..b6a9210 --- /dev/null +++ b/vendor/github.com/aead/siphash/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Andreas Auernhammer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/aead/siphash/README.md b/vendor/github.com/aead/siphash/README.md new file mode 100644 index 0000000..e308419 --- /dev/null +++ b/vendor/github.com/aead/siphash/README.md @@ -0,0 +1,55 @@ +[![Godoc Reference](https://godoc.org/github.com/aead/siphash?status.svg)](https://godoc.org/github.com/aead/siphash) +[![Build Status](https://travis-ci.org/aead/siphash.svg?branch=master)](https://travis-ci.org/aead/siphash) + +## The SipHash pseudo-random function + +SipHash is a family of pseudo-random functions (a.k.a. keyed hash functions) optimized for speed on short messages. +SipHash computes a 64-bit or 128 bit message authentication code from a variable-length message and 128-bit secret key. +This implementation uses the recommended parameters c=2 and d=4. + +### Installation +Install in your GOPATH: `go get -u github.com/aead/siphash` + +### Performance +**AMD64** +Hardware: Intel i7-6500U 2.50GHz x 2 +System: Linux Ubuntu 16.04 - kernel: 4.4.0-67-generic +Go version: 1.8.0 +``` +name speed cpb +Write_8-4 688MB/s ± 0% 3.47 +Write_1K-4 2.09GB/s ± 5% 1.11 +Sum64_8-4 244MB/s ± 1% 9.77 +Sum64_1K-4 2.06GB/s ± 0% 1.13 +Sum128_8-4 189MB/s ± 0% 12.62 +Sum128_1K-4 2.03GB/s ± 0% 1.15 +``` + +**386** +Hardware: Intel i7-6500U 2.50GHz x 2 - SSE2 SIMD +System: Linux Ubuntu 16.04 - kernel: 4.4.0-67-generic +Go version: 1.8.0 +``` +name speed cpb +Write_8-4 434MB/s ± 2% 5.44 +Write_1K-4 1.24GB/s ± 1% 1.88 +Sum64_8-4 92.6MB/s ± 4% 25.92 +Sum64_1K-4 1.15GB/s ± 1% 2.03 +Sum128_8-4 61.5MB/s ± 5% 39.09 +Sum128_1K-4 1.10GB/s ± 0% 2.12 +``` + +**ARM** +Hardware: ARM-Cortex-A7 (ARMv7) 1GHz (912MHz) x 2 +System: Linux Ubuntu 14.04.1 - kernel: 3.4.112-sun7i +Go version: 1.7.4 + +``` +name speed cpb +Write_8-2 43.4MB/s ± 2% 21.97 +Write_1K-2 125MB/s ± 1% 7.63 +Sum64_8-2 6.51MB/s ± 1% 146.49 +Sum64_1K-2 111MB/s ± 1% 8.59 +Sum128_8-2 3.82MB/s ± 2% 249.65 +Sum128_1K-2 101MB/s ± 1% 9.44 +``` diff --git a/vendor/github.com/aead/siphash/siphash.go b/vendor/github.com/aead/siphash/siphash.go new file mode 100644 index 0000000..3aade42 --- /dev/null +++ b/vendor/github.com/aead/siphash/siphash.go @@ -0,0 +1,157 @@ +// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. +// Use of this source code is governed by a license that can be +// found in the LICENSE file. + +// Package siphash implements the SipHash-64 and SipHash-128 +// pseudo-random-functions - with the recommended parameters: +// c = 2 and d = 4. +// SipHash computes a message authentication code (MAC) from a +// variable-length message and a 128 bit secret key. SipHash +// was designed to be efficient, even for short inputs, with +// performance comparable to non-cryptographic hash functions. +// +// +// Security +// +// SipHash cannot be used as a cryptographic hash function. +// Neither SipHash-64 nor SipHash-128 are strong collision +// resistant. +// +// +// Recommendations +// +// SipHash was designed to defend hash flooding DoS attacks. +// SipHash-64 can be used as hashing scheme within hash maps +// or other key-value data structures. +// SipHash-128 can be used to compute a 128 bit authentication +// tag for messages. +package siphash // import "github.com/aead/siphash" + +import ( + "encoding/binary" + "hash" + "strconv" +) + +const ( + // KeySize is the size of the SipHash secret key in bytes. + KeySize = 16 + // BlockSize is the block size of SipHash in bytes. + BlockSize = 8 +) + +const ( + c0 = 0x736f6d6570736575 + c1 = 0x646f72616e646f6d + c2 = 0x6c7967656e657261 + c3 = 0x7465646279746573 +) + +type KeySizeError uint + +func (k KeySizeError) Error() string { + return "siphash: invalid key size " + strconv.Itoa(int(k)) +} + +// Sum64 returns the 64 bit authenticator for msg using a 128 bit secret key. +func Sum64(msg []byte, key *[KeySize]byte) uint64 { + k0 := binary.LittleEndian.Uint64(key[0:]) + k1 := binary.LittleEndian.Uint64(key[8:]) + + var hVal [4]uint64 + hVal[0] = k0 ^ c0 + hVal[1] = k1 ^ c1 + hVal[2] = k0 ^ c2 + hVal[3] = k1 ^ c3 + + n := len(msg) + ctr := byte(n) + + if n >= BlockSize { + n &= (^(BlockSize - 1)) + core(&hVal, msg[:n]) + msg = msg[n:] + } + + var block [BlockSize]byte + copy(block[:], msg) + block[7] = ctr + + return finalize64(&hVal, &block) +} + +// New64 returns a hash.Hash64 computing the SipHash-64 checksum. +// This function returns a non-nil error if len(key) != 16. +func New64(key []byte) (hash.Hash64, error) { + if k := len(key); k != KeySize { + return nil, KeySizeError(k) + } + h := new(digest64) + h.key[0] = binary.LittleEndian.Uint64(key) + h.key[1] = binary.LittleEndian.Uint64(key[8:]) + h.Reset() + return h, nil +} + +type digest64 struct { + hVal [4]uint64 + key [2]uint64 + block [BlockSize]byte + off int + ctr byte +} + +func (d *digest64) BlockSize() int { return BlockSize } + +func (d *digest64) Size() int { return 8 } + +func (d *digest64) Reset() { + d.hVal[0] = d.key[0] ^ c0 + d.hVal[1] = d.key[1] ^ c1 + d.hVal[2] = d.key[0] ^ c2 + d.hVal[3] = d.key[1] ^ c3 + + d.off = 0 + d.ctr = 0 +} + +func (d *digest64) Write(p []byte) (n int, err error) { + n = len(p) + d.ctr += byte(n) + + if d.off > 0 { + dif := BlockSize - d.off + if n < dif { + d.off += copy(d.block[d.off:], p) + return + } + copy(d.block[d.off:], p[:dif]) + core(&(d.hVal), d.block[:]) + p = p[dif:] + d.off = 0 + } + if nn := len(p) &^ (BlockSize - 1); nn >= BlockSize { + core(&(d.hVal), p[:nn]) + p = p[nn:] + } + if len(p) > 0 { + d.off = copy(d.block[:], p) + } + return n, nil +} + +func (d *digest64) Sum64() uint64 { + hVal := d.hVal + block := d.block + for i := d.off; i < BlockSize-1; i++ { + block[i] = 0 + } + block[7] = d.ctr + return finalize64(&hVal, &block) +} + +func (d *digest64) Sum(sum []byte) []byte { + var out [8]byte + binary.LittleEndian.PutUint64(out[:], d.Sum64()) + return append(sum, out[:]...) +} diff --git a/vendor/github.com/aead/siphash/siphash128.go b/vendor/github.com/aead/siphash/siphash128.go new file mode 100644 index 0000000..1dc623f --- /dev/null +++ b/vendor/github.com/aead/siphash/siphash128.go @@ -0,0 +1,106 @@ +// Copyright (c) 2017 Andreas Auernhammer. All rights reserved. +// Use of this source code is governed by a license that can be +// found in the LICENSE file. + +package siphash + +import ( + "encoding/binary" + "hash" +) + +// Sum128 returns the 128 bit authenticator for msg using a 128 bit secret key. +func Sum128(msg []byte, key *[KeySize]byte) [16]byte { + k0 := binary.LittleEndian.Uint64(key[0:]) + k1 := binary.LittleEndian.Uint64(key[8:]) + + var hVal [4]uint64 + hVal[0] = k0 ^ c0 + hVal[1] = k1 ^ c1 ^ 0xee + hVal[2] = k0 ^ c2 + hVal[3] = k1 ^ c3 + + n := len(msg) + ctr := byte(n) + + if n >= BlockSize { + n &= (^(BlockSize - 1)) + core(&hVal, msg[:n]) + msg = msg[n:] + } + + var block [BlockSize]byte + copy(block[:], msg) + block[7] = ctr + + var out [16]byte + finalize128(&out, &hVal, &block) + return out +} + +// New128 returns a hash.Hash computing the SipHash-128 checksum. +// This function returns a non-nil error if len(key) != 16. +func New128(key []byte) (hash.Hash, error) { + if k := len(key); k != KeySize { + return nil, KeySizeError(k) + } + h := new(digest128) + h.key[0] = binary.LittleEndian.Uint64(key) + h.key[1] = binary.LittleEndian.Uint64(key[8:]) + h.Reset() + return h, nil +} + +type digest128 digest64 + +func (d *digest128) BlockSize() int { return BlockSize } + +func (d *digest128) Size() int { return 16 } + +func (d *digest128) Reset() { + d.hVal[0] = d.key[0] ^ c0 + d.hVal[1] = d.key[1] ^ c1 ^ 0xee + d.hVal[2] = d.key[0] ^ c2 + d.hVal[3] = d.key[1] ^ c3 + + d.off = 0 + d.ctr = 0 +} + +func (d *digest128) Write(p []byte) (n int, err error) { + n = len(p) + d.ctr += byte(n) + + if d.off > 0 { + dif := BlockSize - d.off + if n < dif { + d.off += copy(d.block[d.off:], p) + return + } + copy(d.block[d.off:], p[:dif]) + core(&(d.hVal), d.block[:]) + p = p[dif:] + d.off = 0 + } + if nn := len(p) &^ (BlockSize - 1); nn >= BlockSize { + core(&(d.hVal), p[:nn]) + p = p[nn:] + } + if len(p) > 0 { + d.off = copy(d.block[:], p) + } + return n, nil +} + +func (d *digest128) Sum(sum []byte) []byte { + hVal := d.hVal + block := d.block + for i := d.off; i < BlockSize-1; i++ { + block[i] = 0 + } + block[7] = d.ctr + + var out [16]byte + finalize128(&out, &hVal, &block) + return append(sum, out[:]...) +} diff --git a/vendor/github.com/aead/siphash/siphash_386.go b/vendor/github.com/aead/siphash/siphash_386.go new file mode 100644 index 0000000..544ae03 --- /dev/null +++ b/vendor/github.com/aead/siphash/siphash_386.go @@ -0,0 +1,31 @@ +// Copyright (c) 2017 Andreas Auernhammer. All rights reserved. +// Use of this source code is governed by a license that can be +// found in the LICENSE file. + +// +build 386, !gccgo, !appengine + +package siphash + +var useSSE2 = supportsSSE2() + +//go:noescape +func supportsSSE2() bool + +//go:noescape +func coreSSE2(hVal *[4]uint64, msg []byte) + +func core(hVal *[4]uint64, msg []byte) { + if useSSE2 { + coreSSE2(hVal, msg) + } else { + genericCore(hVal, msg) + } +} + +func finalize64(hVal *[4]uint64, block *[BlockSize]byte) uint64 { + return genericFinalize64(hVal, block) +} + +func finalize128(tag *[16]byte, hVal *[4]uint64, block *[BlockSize]byte) { + genericFinalize128(tag, hVal, block) +} diff --git a/vendor/github.com/aead/siphash/siphash_386.s b/vendor/github.com/aead/siphash/siphash_386.s new file mode 100644 index 0000000..ea008a3 --- /dev/null +++ b/vendor/github.com/aead/siphash/siphash_386.s @@ -0,0 +1,65 @@ +// Copyright (c) 2017 Andreas Auernhammer. All rights reserved. +// Use of this source code is governed by a license that can be +// found in the LICENSE file. + +// +build 386, !gccgo, !appengine + +#define ROTL(n, t, v) \ + MOVO v, t; \ + PSLLQ $n, t; \ + PSRLQ $(64-n), v; \ + PXOR t, v + +#define ROUND(v0, v1, v2, v3, t0, t1) \ + PADDQ v1, v0; \ + PADDQ v3, v2; \ + ROTL(13, t0, v1); \ + ROTL(16, t1, v3); \ + PXOR v0, v1; \ + PXOR v2, v3; \ + PSHUFD $0xE1, v0, v0; \ + PADDQ v1, v2; \ + PADDQ v3, v0; \ + ROTL(17, t0, v1); \ + ROTL(21, t1, v3); \ + PXOR v2, v1; \ + PXOR v0, v3; \ + PSHUFD $0xE1, v2, v2 + +// coreSSE2(hVal *[4]uint64, msg []byte) +TEXT ·coreSSE2(SB), 4, $0-16 + MOVL hVal+0(FP), AX + MOVL msg_base+4(FP), SI + MOVL msg_len+8(FP), BX + MOVQ 0(AX), X0 + MOVQ 8(AX), X1 + MOVQ 16(AX), X2 + MOVQ 24(AX), X3 + PXOR X6, X6 + ANDL $-8, BX + +loop: + MOVQ 0(SI), X6 + PXOR X6, X3 + ROUND(X0, X1, X2, X3, X4, X5) + ROUND(X0, X1, X2, X3, X4, X5) + PXOR X6, X0 + + LEAL 8(SI), SI + SUBL $8, BX + JNZ loop + + MOVQ X0, 0(AX) + MOVQ X1, 8(AX) + MOVQ X2, 16(AX) + MOVQ X3, 24(AX) + RET + +// func supportsSSE2() bool +TEXT ·supportsSSE2(SB), 4, $0-1 + MOVL $1, AX + CPUID + SHRL $26, DX + ANDL $1, DX // DX != 0 if support SSE2 + MOVB DX, ret+0(FP) + RET diff --git a/vendor/github.com/aead/siphash/siphash_amd64.go b/vendor/github.com/aead/siphash/siphash_amd64.go new file mode 100644 index 0000000..c18c870 --- /dev/null +++ b/vendor/github.com/aead/siphash/siphash_amd64.go @@ -0,0 +1,18 @@ +// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. +// Use of this source code is governed by a license that can be +// found in the LICENSE file. + +// +build amd64, !gccgo, !appengine + +package siphash + +//go:noescape +func core(hVal *[4]uint64, msg []byte) + +func finalize64(hVal *[4]uint64, block *[BlockSize]byte) uint64 { + return genericFinalize64(hVal, block) +} + +func finalize128(tag *[16]byte, hVal *[4]uint64, block *[BlockSize]byte) { + genericFinalize128(tag, hVal, block) +} diff --git a/vendor/github.com/aead/siphash/siphash_amd64.s b/vendor/github.com/aead/siphash/siphash_amd64.s new file mode 100644 index 0000000..9aa6905 --- /dev/null +++ b/vendor/github.com/aead/siphash/siphash_amd64.s @@ -0,0 +1,49 @@ +// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. +// Use of this source code is governed by a license that can be +// found in the LICENSE file. + +// +build amd64, !gccgo, !appengine + +#define ROUND(v0, v1, v2, v3) \ + ADDQ v1, v0; \ + ADDQ v3, v2; \ + ROLQ $13, v1; \ + ROLQ $16, v3; \ + XORQ v0, v1; \ + XORQ v2, v3; \ + ROLQ $32, v0; \ + ADDQ v1, v2; \ + ADDQ v3, v0; \ + ROLQ $17, v1; \ + ROLQ $21, v3; \ + XORQ v2, v1; \ + XORQ v0, v3; \ + ROLQ $32, v2 + +// core(hVal *[4]uint64, msg []byte) +TEXT ·core(SB), 4, $0-32 + MOVQ hVal+0(FP), AX + MOVQ msg_base+8(FP), SI + MOVQ msg_len+16(FP), BX + MOVQ 0(AX), R9 + MOVQ 8(AX), R10 + MOVQ 16(AX), R11 + MOVQ 24(AX), R12 + ANDQ $-8, BX + +loop: + MOVQ 0(SI), DX + XORQ DX, R12 + ROUND(R9, R10, R11, R12) + ROUND(R9, R10, R11, R12) + XORQ DX, R9 + + LEAQ 8(SI), SI + SUBQ $8, BX + JNZ loop + + MOVQ R9, 0(AX) + MOVQ R10, 8(AX) + MOVQ R11, 16(AX) + MOVQ R12, 24(AX) + RET diff --git a/vendor/github.com/aead/siphash/siphash_generic.go b/vendor/github.com/aead/siphash/siphash_generic.go new file mode 100644 index 0000000..139a33f --- /dev/null +++ b/vendor/github.com/aead/siphash/siphash_generic.go @@ -0,0 +1,188 @@ +// Copyright (c) 2017 Andreas Auernhammer. All rights reserved. +// Use of this source code is governed by a license that can be +// found in the LICENSE file. + +package siphash + +import "encoding/binary" + +func genericCore(hVal *[4]uint64, msg []byte) { + v0, v1, v2, v3 := hVal[0], hVal[1], hVal[2], hVal[3] + + for len(msg) > 0 { + m := binary.LittleEndian.Uint64(msg) + msg = msg[BlockSize:] + + v3 ^= m + + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + v0 ^= m + } + + hVal[0], hVal[1], hVal[2], hVal[3] = v0, v1, v2, v3 +} + +func genericFinalize64(hVal *[4]uint64, block *[BlockSize]byte) uint64 { + v0, v1, v2, v3 := hVal[0], hVal[1], hVal[2], hVal[3] + + m := binary.LittleEndian.Uint64(block[:]) + v3 ^= m + + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + v0 ^= m + + v2 ^= 0xff + for i := 0; i < 4; i++ { + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + } + return v0 ^ v1 ^ v2 ^ v3 +} + +func genericFinalize128(tag *[16]byte, hVal *[4]uint64, block *[BlockSize]byte) { + v0, v1, v2, v3 := hVal[0], hVal[1], hVal[2], hVal[3] + + m := binary.LittleEndian.Uint64(block[:]) + + v3 ^= m + + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + + v0 ^= m + + v2 ^= 0xee + for i := 0; i < 4; i++ { + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + } + binary.LittleEndian.PutUint64(tag[:], v0^v1^v2^v3) + + v1 ^= 0xdd + for i := 0; i < 4; i++ { + v0 += v1 + v1 = v1<<13 | v1>>(64-13) + v1 ^= v0 + v0 = v0<<32 | v0>>(64-32) + v2 += v3 + v3 = v3<<16 | v3>>(64-16) + v3 ^= v2 + v0 += v3 + v3 = v3<<21 | v3>>(64-21) + v3 ^= v0 + v2 += v1 + v1 = v1<<17 | v1>>(64-17) + v1 ^= v2 + v2 = v2<<32 | v2>>(64-32) + } + binary.LittleEndian.PutUint64(tag[8:], v0^v1^v2^v3) +} diff --git a/vendor/github.com/aead/siphash/siphash_ref.go b/vendor/github.com/aead/siphash/siphash_ref.go new file mode 100644 index 0000000..3627bb9 --- /dev/null +++ b/vendor/github.com/aead/siphash/siphash_ref.go @@ -0,0 +1,19 @@ +// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. +// Use of this source code is governed by a license that can be +// found in the LICENSE file. + +// +build !amd64,!386 gccgo appengine nacl + +package siphash + +func core(hVal *[4]uint64, msg []byte) { + genericCore(hVal, msg) +} + +func finalize64(hVal *[4]uint64, block *[BlockSize]byte) uint64 { + return genericFinalize64(hVal, block) +} + +func finalize128(tag *[16]byte, hVal *[4]uint64, block *[BlockSize]byte) { + genericFinalize128(tag, hVal, block) +} diff --git a/vendor/github.com/btcsuite/btcd/LICENSE b/vendor/github.com/btcsuite/btcd/LICENSE new file mode 100644 index 0000000..53ba0c5 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/LICENSE @@ -0,0 +1,16 @@ +ISC License + +Copyright (c) 2013-2017 The btcsuite developers +Copyright (c) 2015-2016 The Decred developers + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/btcsuite/btcd/addrmgr/addrmanager.go b/vendor/github.com/btcsuite/btcd/addrmgr/addrmanager.go new file mode 100644 index 0000000..a8a8fb3 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/addrmgr/addrmanager.go @@ -0,0 +1,1151 @@ +// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package addrmgr + +import ( + "container/list" + crand "crypto/rand" // for seeding + "encoding/base32" + "encoding/binary" + "encoding/json" + "fmt" + "io" + "math/rand" + "net" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" +) + +// AddrManager provides a concurrency safe address manager for caching potential +// peers on the bitcoin network. +type AddrManager struct { + mtx sync.Mutex + peersFile string + lookupFunc func(string) ([]net.IP, error) + rand *rand.Rand + key [32]byte + addrIndex map[string]*KnownAddress // address key to ka for all addrs. + addrNew [newBucketCount]map[string]*KnownAddress + addrTried [triedBucketCount]*list.List + started int32 + shutdown int32 + wg sync.WaitGroup + quit chan struct{} + nTried int + nNew int + lamtx sync.Mutex + localAddresses map[string]*localAddress + version int +} + +type serializedKnownAddress struct { + Addr string + Src string + Attempts int + TimeStamp int64 + LastAttempt int64 + LastSuccess int64 + Services wire.ServiceFlag + SrcServices wire.ServiceFlag + // no refcount or tried, that is available from context. +} + +type serializedAddrManager struct { + Version int + Key [32]byte + Addresses []*serializedKnownAddress + NewBuckets [newBucketCount][]string // string is NetAddressKey + TriedBuckets [triedBucketCount][]string +} + +type localAddress struct { + na *wire.NetAddress + score AddressPriority +} + +// AddressPriority type is used to describe the hierarchy of local address +// discovery methods. +type AddressPriority int + +const ( + // InterfacePrio signifies the address is on a local interface + InterfacePrio AddressPriority = iota + + // BoundPrio signifies the address has been explicitly bounded to. + BoundPrio + + // UpnpPrio signifies the address was obtained from UPnP. + UpnpPrio + + // HTTPPrio signifies the address was obtained from an external HTTP service. + HTTPPrio + + // ManualPrio signifies the address was provided by --externalip. + ManualPrio +) + +const ( + // needAddressThreshold is the number of addresses under which the + // address manager will claim to need more addresses. + needAddressThreshold = 1000 + + // dumpAddressInterval is the interval used to dump the address + // cache to disk for future use. + dumpAddressInterval = time.Minute * 10 + + // triedBucketSize is the maximum number of addresses in each + // tried address bucket. + triedBucketSize = 256 + + // triedBucketCount is the number of buckets we split tried + // addresses over. + triedBucketCount = 64 + + // newBucketSize is the maximum number of addresses in each new address + // bucket. + newBucketSize = 64 + + // newBucketCount is the number of buckets that we spread new addresses + // over. + newBucketCount = 1024 + + // triedBucketsPerGroup is the number of tried buckets over which an + // address group will be spread. + triedBucketsPerGroup = 8 + + // newBucketsPerGroup is the number of new buckets over which an + // source address group will be spread. + newBucketsPerGroup = 64 + + // newBucketsPerAddress is the number of buckets a frequently seen new + // address may end up in. + newBucketsPerAddress = 8 + + // numMissingDays is the number of days before which we assume an + // address has vanished if we have not seen it announced in that long. + numMissingDays = 30 + + // numRetries is the number of tried without a single success before + // we assume an address is bad. + numRetries = 3 + + // maxFailures is the maximum number of failures we will accept without + // a success before considering an address bad. + maxFailures = 10 + + // minBadDays is the number of days since the last success before we + // will consider evicting an address. + minBadDays = 7 + + // getAddrMax is the most addresses that we will send in response + // to a getAddr (in practise the most addresses we will return from a + // call to AddressCache()). + getAddrMax = 2500 + + // getAddrPercent is the percentage of total addresses known that we + // will share with a call to AddressCache. + getAddrPercent = 23 + + // serialisationVersion is the current version of the on-disk format. + serialisationVersion = 2 +) + +// updateAddress is a helper function to either update an address already known +// to the address manager, or to add the address if not already known. +func (a *AddrManager) updateAddress(netAddr, srcAddr *wire.NetAddress) { + // Filter out non-routable addresses. Note that non-routable + // also includes invalid and local addresses. + if !IsRoutable(netAddr) { + return + } + + addr := NetAddressKey(netAddr) + ka := a.find(netAddr) + if ka != nil { + // 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*, + // 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. + if netAddr.Timestamp.After(ka.na.Timestamp) || + (ka.na.Services&netAddr.Services) != + netAddr.Services { + + naCopy := *ka.na + naCopy.Timestamp = netAddr.Timestamp + naCopy.AddService(netAddr.Services) + ka.na = &naCopy + } + + // If already in tried, we have nothing to do here. + if ka.tried { + return + } + + // Already at our max? + if ka.refs == newBucketsPerAddress { + return + } + + // The more entries we have, the less likely we are to add more. + // likelihood is 2N. + factor := int32(2 * ka.refs) + if a.rand.Int31n(factor) != 0 { + return + } + } else { + // Make a copy of the net address to avoid races since it is + // updated elsewhere in the addrmanager code and would otherwise + // change the actual netaddress on the peer. + netAddrCopy := *netAddr + ka = &KnownAddress{na: &netAddrCopy, srcAddr: srcAddr} + a.addrIndex[addr] = ka + a.nNew++ + // XXX time penalty? + } + + bucket := a.getNewBucket(netAddr, srcAddr) + + // Already exists? + if _, ok := a.addrNew[bucket][addr]; ok { + return + } + + // Enforce max addresses. + if len(a.addrNew[bucket]) > newBucketSize { + log.Tracef("new bucket is full, expiring old") + a.expireNew(bucket) + } + + // Add to new bucket. + ka.refs++ + a.addrNew[bucket][addr] = ka + + log.Tracef("Added new address %s for a total of %d addresses", addr, + a.nTried+a.nNew) +} + +// expireNew makes space in the new buckets by expiring the really bad entries. +// If no bad entries are available we look at a few and remove the oldest. +func (a *AddrManager) expireNew(bucket int) { + // First see if there are any entries that are so bad we can just throw + // them away. otherwise we throw away the oldest entry in the cache. + // Bitcoind here chooses four random and just throws the oldest of + // those away, but we keep track of oldest in the initial traversal and + // use that information instead. + var oldest *KnownAddress + for k, v := range a.addrNew[bucket] { + if v.isBad() { + log.Tracef("expiring bad address %v", k) + delete(a.addrNew[bucket], k) + v.refs-- + if v.refs == 0 { + a.nNew-- + delete(a.addrIndex, k) + } + continue + } + if oldest == nil { + oldest = v + } else if !v.na.Timestamp.After(oldest.na.Timestamp) { + oldest = v + } + } + + if oldest != nil { + key := NetAddressKey(oldest.na) + log.Tracef("expiring oldest address %v", key) + + delete(a.addrNew[bucket], key) + oldest.refs-- + if oldest.refs == 0 { + a.nNew-- + delete(a.addrIndex, key) + } + } +} + +// pickTried selects an address from the tried bucket to be evicted. +// We just choose the eldest. Bitcoind selects 4 random entries and throws away +// the older of them. +func (a *AddrManager) pickTried(bucket int) *list.Element { + var oldest *KnownAddress + var oldestElem *list.Element + for e := a.addrTried[bucket].Front(); e != nil; e = e.Next() { + ka := e.Value.(*KnownAddress) + if oldest == nil || oldest.na.Timestamp.After(ka.na.Timestamp) { + oldestElem = e + oldest = ka + } + + } + return oldestElem +} + +func (a *AddrManager) getNewBucket(netAddr, srcAddr *wire.NetAddress) int { + // bitcoind: + // doublesha256(key + sourcegroup + int64(doublesha256(key + group + sourcegroup))%bucket_per_source_group) % num_new_buckets + + data1 := []byte{} + data1 = append(data1, a.key[:]...) + data1 = append(data1, []byte(GroupKey(netAddr))...) + data1 = append(data1, []byte(GroupKey(srcAddr))...) + hash1 := chainhash.DoubleHashB(data1) + hash64 := binary.LittleEndian.Uint64(hash1) + hash64 %= newBucketsPerGroup + var hashbuf [8]byte + binary.LittleEndian.PutUint64(hashbuf[:], hash64) + data2 := []byte{} + data2 = append(data2, a.key[:]...) + data2 = append(data2, GroupKey(srcAddr)...) + data2 = append(data2, hashbuf[:]...) + + hash2 := chainhash.DoubleHashB(data2) + return int(binary.LittleEndian.Uint64(hash2) % newBucketCount) +} + +func (a *AddrManager) getTriedBucket(netAddr *wire.NetAddress) int { + // bitcoind hashes this as: + // doublesha256(key + group + truncate_to_64bits(doublesha256(key)) % buckets_per_group) % num_buckets + data1 := []byte{} + data1 = append(data1, a.key[:]...) + data1 = append(data1, []byte(NetAddressKey(netAddr))...) + hash1 := chainhash.DoubleHashB(data1) + hash64 := binary.LittleEndian.Uint64(hash1) + hash64 %= triedBucketsPerGroup + var hashbuf [8]byte + binary.LittleEndian.PutUint64(hashbuf[:], hash64) + data2 := []byte{} + data2 = append(data2, a.key[:]...) + data2 = append(data2, GroupKey(netAddr)...) + data2 = append(data2, hashbuf[:]...) + + hash2 := chainhash.DoubleHashB(data2) + return int(binary.LittleEndian.Uint64(hash2) % triedBucketCount) +} + +// addressHandler is the main handler for the address manager. It must be run +// as a goroutine. +func (a *AddrManager) addressHandler() { + dumpAddressTicker := time.NewTicker(dumpAddressInterval) + defer dumpAddressTicker.Stop() +out: + for { + select { + case <-dumpAddressTicker.C: + a.savePeers() + + case <-a.quit: + break out + } + } + a.savePeers() + a.wg.Done() + log.Trace("Address handler done") +} + +// savePeers saves all the known addresses to a file so they can be read back +// in at next run. +func (a *AddrManager) savePeers() { + a.mtx.Lock() + defer a.mtx.Unlock() + + // First we make a serialisable datastructure so we can encode it to + // json. + sam := new(serializedAddrManager) + sam.Version = a.version + copy(sam.Key[:], a.key[:]) + + sam.Addresses = make([]*serializedKnownAddress, len(a.addrIndex)) + i := 0 + for k, v := range a.addrIndex { + ska := new(serializedKnownAddress) + ska.Addr = k + ska.TimeStamp = v.na.Timestamp.Unix() + ska.Src = NetAddressKey(v.srcAddr) + ska.Attempts = v.attempts + ska.LastAttempt = v.lastattempt.Unix() + ska.LastSuccess = v.lastsuccess.Unix() + if a.version > 1 { + ska.Services = v.na.Services + ska.SrcServices = v.srcAddr.Services + } + // Tried and refs are implicit in the rest of the structure + // and will be worked out from context on unserialisation. + sam.Addresses[i] = ska + i++ + } + for i := range a.addrNew { + sam.NewBuckets[i] = make([]string, len(a.addrNew[i])) + j := 0 + for k := range a.addrNew[i] { + sam.NewBuckets[i][j] = k + j++ + } + } + for i := range a.addrTried { + sam.TriedBuckets[i] = make([]string, a.addrTried[i].Len()) + j := 0 + for e := a.addrTried[i].Front(); e != nil; e = e.Next() { + ka := e.Value.(*KnownAddress) + sam.TriedBuckets[i][j] = NetAddressKey(ka.na) + j++ + } + } + + w, err := os.Create(a.peersFile) + if err != nil { + log.Errorf("Error opening file %s: %v", a.peersFile, err) + return + } + enc := json.NewEncoder(w) + defer w.Close() + if err := enc.Encode(&sam); err != nil { + log.Errorf("Failed to encode file %s: %v", a.peersFile, err) + return + } +} + +// loadPeers loads the known address from the saved file. If empty, missing, or +// malformed file, just don't load anything and start fresh +func (a *AddrManager) loadPeers() { + a.mtx.Lock() + defer a.mtx.Unlock() + + err := a.deserializePeers(a.peersFile) + if err != nil { + log.Errorf("Failed to parse file %s: %v", a.peersFile, err) + // if it is invalid we nuke the old one unconditionally. + err = os.Remove(a.peersFile) + if err != nil { + log.Warnf("Failed to remove corrupt peers file %s: %v", + a.peersFile, err) + } + a.reset() + return + } + log.Infof("Loaded %d addresses from file '%s'", a.numAddresses(), a.peersFile) +} + +func (a *AddrManager) deserializePeers(filePath string) error { + + _, err := os.Stat(filePath) + if os.IsNotExist(err) { + return nil + } + r, err := os.Open(filePath) + if err != nil { + return fmt.Errorf("%s error opening file: %v", filePath, err) + } + defer r.Close() + + var sam serializedAddrManager + dec := json.NewDecoder(r) + err = dec.Decode(&sam) + if err != nil { + return fmt.Errorf("error reading %s: %v", filePath, err) + } + + // Since decoding JSON is backwards compatible (i.e., only decodes + // fields it understands), we'll only return an error upon seeing a + // version past our latest supported version. + if sam.Version > serialisationVersion { + return fmt.Errorf("unknown version %v in serialized "+ + "addrmanager", sam.Version) + } + + copy(a.key[:], sam.Key[:]) + + for _, v := range sam.Addresses { + ka := new(KnownAddress) + + // The first version of the serialized address manager was not + // aware of the service bits associated with this address, so + // we'll assign a default of SFNodeNetwork to it. + if sam.Version == 1 { + v.Services = wire.SFNodeNetwork + } + ka.na, err = a.DeserializeNetAddress(v.Addr, v.Services) + if err != nil { + return fmt.Errorf("failed to deserialize netaddress "+ + "%s: %v", v.Addr, err) + } + + // The first version of the serialized address manager was not + // aware of the service bits associated with the source address, + // so we'll assign a default of SFNodeNetwork to it. + if sam.Version == 1 { + v.SrcServices = wire.SFNodeNetwork + } + ka.srcAddr, err = a.DeserializeNetAddress(v.Src, v.SrcServices) + if err != nil { + return fmt.Errorf("failed to deserialize netaddress "+ + "%s: %v", v.Src, err) + } + + ka.attempts = v.Attempts + ka.lastattempt = time.Unix(v.LastAttempt, 0) + ka.lastsuccess = time.Unix(v.LastSuccess, 0) + a.addrIndex[NetAddressKey(ka.na)] = ka + } + + for i := range sam.NewBuckets { + for _, val := range sam.NewBuckets[i] { + ka, ok := a.addrIndex[val] + if !ok { + return fmt.Errorf("newbucket contains %s but "+ + "none in address list", val) + } + + if ka.refs == 0 { + a.nNew++ + } + ka.refs++ + a.addrNew[i][val] = ka + } + } + for i := range sam.TriedBuckets { + for _, val := range sam.TriedBuckets[i] { + ka, ok := a.addrIndex[val] + if !ok { + return fmt.Errorf("Newbucket contains %s but "+ + "none in address list", val) + } + + ka.tried = true + a.nTried++ + a.addrTried[i].PushBack(ka) + } + } + + // Sanity checking. + for k, v := range a.addrIndex { + if v.refs == 0 && !v.tried { + return fmt.Errorf("address %s after serialisation "+ + "with no references", k) + } + + if v.refs > 0 && v.tried { + return fmt.Errorf("address %s after serialisation "+ + "which is both new and tried!", k) + } + } + + return nil +} + +// DeserializeNetAddress converts a given address string to a *wire.NetAddress. +func (a *AddrManager) DeserializeNetAddress(addr string, + services wire.ServiceFlag) (*wire.NetAddress, error) { + + host, portStr, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + port, err := strconv.ParseUint(portStr, 10, 16) + if err != nil { + return nil, err + } + + return a.HostToNetAddress(host, uint16(port), services) +} + +// Start begins the core address handler which manages a pool of known +// addresses, timeouts, and interval based writes. +func (a *AddrManager) Start() { + // Already started? + if atomic.AddInt32(&a.started, 1) != 1 { + return + } + + log.Trace("Starting address manager") + + // Load peers we already know about from file. + a.loadPeers() + + // Start the address ticker to save addresses periodically. + a.wg.Add(1) + go a.addressHandler() +} + +// Stop gracefully shuts down the address manager by stopping the main handler. +func (a *AddrManager) Stop() error { + if atomic.AddInt32(&a.shutdown, 1) != 1 { + log.Warnf("Address manager is already in the process of " + + "shutting down") + return nil + } + + log.Infof("Address manager shutting down") + close(a.quit) + a.wg.Wait() + return nil +} + +// AddAddresses adds new addresses to the address manager. It enforces a max +// number of addresses and silently ignores duplicate addresses. It is +// safe for concurrent access. +func (a *AddrManager) AddAddresses(addrs []*wire.NetAddress, srcAddr *wire.NetAddress) { + a.mtx.Lock() + defer a.mtx.Unlock() + + for _, na := range addrs { + a.updateAddress(na, srcAddr) + } +} + +// AddAddress adds a new address to the address manager. It enforces a max +// number of addresses and silently ignores duplicate addresses. It is +// safe for concurrent access. +func (a *AddrManager) AddAddress(addr, srcAddr *wire.NetAddress) { + a.mtx.Lock() + defer a.mtx.Unlock() + + a.updateAddress(addr, srcAddr) +} + +// AddAddressByIP adds an address where we are given an ip:port and not a +// wire.NetAddress. +func (a *AddrManager) AddAddressByIP(addrIP string) error { + // Split IP and port + addr, portStr, err := net.SplitHostPort(addrIP) + if err != nil { + return err + } + // Put it in wire.Netaddress + ip := net.ParseIP(addr) + if ip == nil { + return fmt.Errorf("invalid ip address %s", addr) + } + port, err := strconv.ParseUint(portStr, 10, 0) + if err != nil { + return fmt.Errorf("invalid port %s: %v", portStr, err) + } + na := wire.NewNetAddressIPPort(ip, uint16(port), 0) + a.AddAddress(na, na) // XXX use correct src address + return nil +} + +// NumAddresses returns the number of addresses known to the address manager. +func (a *AddrManager) numAddresses() int { + return a.nTried + a.nNew +} + +// NumAddresses returns the number of addresses known to the address manager. +func (a *AddrManager) NumAddresses() int { + a.mtx.Lock() + defer a.mtx.Unlock() + + return a.numAddresses() +} + +// NeedMoreAddresses returns whether or not the address manager needs more +// addresses. +func (a *AddrManager) NeedMoreAddresses() bool { + a.mtx.Lock() + defer a.mtx.Unlock() + + return a.numAddresses() < needAddressThreshold +} + +// AddressCache returns the current address cache. It must be treated as +// read-only (but since it is a copy now, this is not as dangerous). +func (a *AddrManager) AddressCache() []*wire.NetAddress { + allAddr := a.getAddresses() + + numAddresses := len(allAddr) * getAddrPercent / 100 + if numAddresses > getAddrMax { + numAddresses = getAddrMax + } + + // Fisher-Yates shuffle the array. We only need to do the first + // `numAddresses' since we are throwing the rest. + for i := 0; i < numAddresses; i++ { + // pick a number between current index and the end + j := rand.Intn(len(allAddr)-i) + i + allAddr[i], allAddr[j] = allAddr[j], allAddr[i] + } + + // slice off the limit we are willing to share. + return allAddr[0:numAddresses] +} + +// getAddresses returns all of the addresses currently found within the +// manager's address cache. +func (a *AddrManager) getAddresses() []*wire.NetAddress { + a.mtx.Lock() + defer a.mtx.Unlock() + + addrIndexLen := len(a.addrIndex) + if addrIndexLen == 0 { + return nil + } + + addrs := make([]*wire.NetAddress, 0, addrIndexLen) + for _, v := range a.addrIndex { + addrs = append(addrs, v.na) + } + + return addrs +} + +// reset resets the address manager by reinitialising the random source +// and allocating fresh empty bucket storage. +func (a *AddrManager) reset() { + + a.addrIndex = make(map[string]*KnownAddress) + + // fill key with bytes from a good random source. + io.ReadFull(crand.Reader, a.key[:]) + for i := range a.addrNew { + a.addrNew[i] = make(map[string]*KnownAddress) + } + for i := range a.addrTried { + a.addrTried[i] = list.New() + } +} + +// HostToNetAddress returns a netaddress given a host address. If the address +// is a Tor .onion address this will be taken care of. Else if the host is +// not an IP address it will be resolved (via Tor if required). +func (a *AddrManager) HostToNetAddress(host string, port uint16, services wire.ServiceFlag) (*wire.NetAddress, error) { + // Tor address is 16 char base32 + ".onion" + var ip net.IP + if len(host) == 22 && host[16:] == ".onion" { + // go base32 encoding uses capitals (as does the rfc + // but Tor and bitcoind tend to user lowercase, so we switch + // case here. + data, err := base32.StdEncoding.DecodeString( + strings.ToUpper(host[:16])) + if err != nil { + return nil, err + } + prefix := []byte{0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43} + ip = net.IP(append(prefix, data...)) + } else if ip = net.ParseIP(host); ip == nil { + ips, err := a.lookupFunc(host) + if err != nil { + return nil, err + } + if len(ips) == 0 { + return nil, fmt.Errorf("no addresses found for %s", host) + } + ip = ips[0] + } + + return wire.NewNetAddressIPPort(ip, port, services), nil +} + +// ipString returns a string for the ip from the provided NetAddress. If the +// ip is in the range used for Tor addresses then it will be transformed into +// the relevant .onion address. +func ipString(na *wire.NetAddress) string { + if IsOnionCatTor(na) { + // We know now that na.IP is long enough. + base32 := base32.StdEncoding.EncodeToString(na.IP[6:]) + return strings.ToLower(base32) + ".onion" + } + + return na.IP.String() +} + +// NetAddressKey returns a string key in the form of ip:port for IPv4 addresses +// or [ip]:port for IPv6 addresses. +func NetAddressKey(na *wire.NetAddress) string { + port := strconv.FormatUint(uint64(na.Port), 10) + + return net.JoinHostPort(ipString(na), port) +} + +// GetAddress returns a single address that should be routable. It picks a +// random one from the possible addresses with preference given to ones that +// have not been used recently and should not pick 'close' addresses +// consecutively. +func (a *AddrManager) GetAddress() *KnownAddress { + // Protect concurrent access. + a.mtx.Lock() + defer a.mtx.Unlock() + + if a.numAddresses() == 0 { + return nil + } + + // Use a 50% chance for choosing between tried and new table entries. + if a.nTried > 0 && (a.nNew == 0 || a.rand.Intn(2) == 0) { + // Tried entry. + large := 1 << 30 + factor := 1.0 + for { + // pick a random bucket. + bucket := a.rand.Intn(len(a.addrTried)) + if a.addrTried[bucket].Len() == 0 { + continue + } + + // Pick a random entry in the list + e := a.addrTried[bucket].Front() + for i := + a.rand.Int63n(int64(a.addrTried[bucket].Len())); i > 0; i-- { + e = e.Next() + } + ka := e.Value.(*KnownAddress) + randval := a.rand.Intn(large) + if float64(randval) < (factor * ka.chance() * float64(large)) { + log.Tracef("Selected %v from tried bucket", + NetAddressKey(ka.na)) + return ka + } + factor *= 1.2 + } + } else { + // new node. + // XXX use a closure/function to avoid repeating this. + large := 1 << 30 + factor := 1.0 + for { + // Pick a random bucket. + bucket := a.rand.Intn(len(a.addrNew)) + if len(a.addrNew[bucket]) == 0 { + continue + } + // Then, a random entry in it. + var ka *KnownAddress + nth := a.rand.Intn(len(a.addrNew[bucket])) + for _, value := range a.addrNew[bucket] { + if nth == 0 { + ka = value + } + nth-- + } + randval := a.rand.Intn(large) + if float64(randval) < (factor * ka.chance() * float64(large)) { + log.Tracef("Selected %v from new bucket", + NetAddressKey(ka.na)) + return ka + } + factor *= 1.2 + } + } +} + +func (a *AddrManager) find(addr *wire.NetAddress) *KnownAddress { + return a.addrIndex[NetAddressKey(addr)] +} + +// Attempt increases the given address' attempt counter and updates +// the last attempt time. +func (a *AddrManager) Attempt(addr *wire.NetAddress) { + a.mtx.Lock() + defer a.mtx.Unlock() + + // find address. + // Surely address will be in tried by now? + ka := a.find(addr) + if ka == nil { + return + } + // set last tried time to now + ka.attempts++ + ka.lastattempt = time.Now() +} + +// Connected Marks the given address as currently connected and working at the +// current time. The address must already be known to AddrManager else it will +// be ignored. +func (a *AddrManager) Connected(addr *wire.NetAddress) { + a.mtx.Lock() + defer a.mtx.Unlock() + + ka := a.find(addr) + if ka == nil { + return + } + + // Update the time as long as it has been 20 minutes since last we did + // so. + now := time.Now() + if now.After(ka.na.Timestamp.Add(time.Minute * 20)) { + // ka.na is immutable, so replace it. + naCopy := *ka.na + naCopy.Timestamp = time.Now() + ka.na = &naCopy + } +} + +// Good marks the given address as good. To be called after a successful +// connection and version exchange. If the address is unknown to the address +// manager it will be ignored. +func (a *AddrManager) Good(addr *wire.NetAddress) { + a.mtx.Lock() + defer a.mtx.Unlock() + + ka := a.find(addr) + if ka == nil { + return + } + + // ka.Timestamp is not updated here to avoid leaking information + // about currently connected peers. + now := time.Now() + ka.lastsuccess = now + ka.lastattempt = now + ka.attempts = 0 + + // move to tried set, optionally evicting other addresses if neeed. + if ka.tried { + return + } + + // ok, need to move it to tried. + + // remove from all new buckets. + // record one of the buckets in question and call it the `first' + addrKey := NetAddressKey(addr) + oldBucket := -1 + for i := range a.addrNew { + // we check for existence so we can record the first one + if _, ok := a.addrNew[i][addrKey]; ok { + delete(a.addrNew[i], addrKey) + ka.refs-- + if oldBucket == -1 { + oldBucket = i + } + } + } + a.nNew-- + + if oldBucket == -1 { + // What? wasn't in a bucket after all.... Panic? + return + } + + bucket := a.getTriedBucket(ka.na) + + // Room in this tried bucket? + if a.addrTried[bucket].Len() < triedBucketSize { + ka.tried = true + a.addrTried[bucket].PushBack(ka) + a.nTried++ + return + } + + // No room, we have to evict something else. + entry := a.pickTried(bucket) + rmka := entry.Value.(*KnownAddress) + + // First bucket it would have been put in. + newBucket := a.getNewBucket(rmka.na, rmka.srcAddr) + + // If no room in the original bucket, we put it in a bucket we just + // freed up a space in. + if len(a.addrNew[newBucket]) >= newBucketSize { + newBucket = oldBucket + } + + // replace with ka in list. + ka.tried = true + entry.Value = ka + + rmka.tried = false + rmka.refs++ + + // We don't touch a.nTried here since the number of tried stays the same + // but we decemented new above, raise it again since we're putting + // something back. + a.nNew++ + + rmkey := NetAddressKey(rmka.na) + log.Tracef("Replacing %s with %s in tried", rmkey, addrKey) + + // We made sure there is space here just above. + a.addrNew[newBucket][rmkey] = rmka +} + +// SetServices sets the services for the giiven address to the provided value. +func (a *AddrManager) SetServices(addr *wire.NetAddress, services wire.ServiceFlag) { + a.mtx.Lock() + defer a.mtx.Unlock() + + ka := a.find(addr) + if ka == nil { + return + } + + // Update the services if needed. + if ka.na.Services != services { + // ka.na is immutable, so replace it. + naCopy := *ka.na + naCopy.Services = services + ka.na = &naCopy + } +} + +// 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) { + return fmt.Errorf("address %s is not routable", na.IP) + } + + a.lamtx.Lock() + defer a.lamtx.Unlock() + + key := NetAddressKey(na) + la, ok := a.localAddresses[key] + if !ok || la.score < priority { + if ok { + la.score = priority + 1 + } else { + a.localAddresses[key] = &localAddress{ + na: na, + score: priority, + } + } + } + return nil +} + +// getReachabilityFrom returns the relative reachability of the provided local +// address to the provided remote address. +func getReachabilityFrom(localAddr, remoteAddr *wire.NetAddress) int { + const ( + Unreachable = 0 + Default = iota + Teredo + Ipv6Weak + Ipv4 + Ipv6Strong + Private + ) + + if !IsRoutable(remoteAddr) { + return Unreachable + } + + if IsOnionCatTor(remoteAddr) { + if IsOnionCatTor(localAddr) { + return Private + } + + if IsRoutable(localAddr) && IsIPv4(localAddr) { + return Ipv4 + } + + return Default + } + + if IsRFC4380(remoteAddr) { + if !IsRoutable(localAddr) { + return Default + } + + if IsRFC4380(localAddr) { + return Teredo + } + + if IsIPv4(localAddr) { + return Ipv4 + } + + return Ipv6Weak + } + + if IsIPv4(remoteAddr) { + if IsRoutable(localAddr) && IsIPv4(localAddr) { + return Ipv4 + } + return Unreachable + } + + /* ipv6 */ + var tunnelled bool + // Is our v6 is tunnelled? + if IsRFC3964(localAddr) || IsRFC6052(localAddr) || IsRFC6145(localAddr) { + tunnelled = true + } + + if !IsRoutable(localAddr) { + return Default + } + + if IsRFC4380(localAddr) { + return Teredo + } + + if IsIPv4(localAddr) { + return Ipv4 + } + + if tunnelled { + // only prioritise ipv6 if we aren't tunnelling it. + return Ipv6Weak + } + + return Ipv6Strong +} + +// GetBestLocalAddress returns the most appropriate local address to use +// for the given remote address. +func (a *AddrManager) GetBestLocalAddress(remoteAddr *wire.NetAddress) *wire.NetAddress { + a.lamtx.Lock() + defer a.lamtx.Unlock() + + bestreach := 0 + var bestscore AddressPriority + var bestAddress *wire.NetAddress + for _, la := range a.localAddresses { + reach := getReachabilityFrom(la.na, remoteAddr) + if reach > bestreach || + (reach == bestreach && la.score > bestscore) { + bestreach = reach + bestscore = la.score + bestAddress = la.na + } + } + if bestAddress != nil { + log.Debugf("Suggesting address %s:%d for %s:%d", bestAddress.IP, + bestAddress.Port, remoteAddr.IP, remoteAddr.Port) + } else { + log.Debugf("No worthy address for %s:%d", remoteAddr.IP, + remoteAddr.Port) + + // Send something unroutable if nothing suitable. + var ip net.IP + if !IsIPv4(remoteAddr) && !IsOnionCatTor(remoteAddr) { + ip = net.IPv6zero + } else { + ip = net.IPv4zero + } + services := wire.SFNodeNetwork | wire.SFNodeWitness | wire.SFNodeBloom + bestAddress = wire.NewNetAddressIPPort(ip, 0, services) + } + + return bestAddress +} + +// 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 { + am := AddrManager{ + peersFile: filepath.Join(dataDir, "peers.json"), + lookupFunc: lookupFunc, + rand: rand.New(rand.NewSource(time.Now().UnixNano())), + quit: make(chan struct{}), + localAddresses: make(map[string]*localAddress), + version: serialisationVersion, + } + am.reset() + return &am +} diff --git a/vendor/github.com/btcsuite/btcd/addrmgr/cov_report.sh b/vendor/github.com/btcsuite/btcd/addrmgr/cov_report.sh new file mode 100644 index 0000000..307f05b --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/addrmgr/cov_report.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# This script uses gocov to generate a test coverage report. +# The gocov tool my be obtained with the following command: +# go get github.com/axw/gocov/gocov +# +# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH. + +# Check for gocov. +type gocov >/dev/null 2>&1 +if [ $? -ne 0 ]; then + echo >&2 "This script requires the gocov tool." + echo >&2 "You may obtain it with the following command:" + echo >&2 "go get github.com/axw/gocov/gocov" + exit 1 +fi +gocov test | gocov report diff --git a/vendor/github.com/btcsuite/btcd/addrmgr/doc.go b/vendor/github.com/btcsuite/btcd/addrmgr/doc.go new file mode 100644 index 0000000..8ddc8bf --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/addrmgr/doc.go @@ -0,0 +1,38 @@ +// Copyright (c) 2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +/* +Package addrmgr implements concurrency safe Bitcoin address manager. + +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 +the getaddr and addr messages to allow peers to communicate known addresses with +each other. However, there needs to a mechanism to store those results and +select peers from them. It is also important to note that remote peers can't +be trusted to send valid peers nor attempt to provide you with only peers they +control with malicious intent. + +With that in mind, this package provides a concurrency safe address manager for +caching and selecting peers in a non-deterministic manner. The general idea is +the caller adds addresses to the address manager and notifies it when addresses +are connected, known good, and attempted. The caller also requests addresses as +it needs them. + +The address manager internally segregates the addresses into groups and +non-deterministically selects groups in a cryptographically random manner. This +reduce the chances multiple addresses from the same nets are selected which +generally helps provide greater peer diversity, and perhaps more importantly, +drastically reduces the chances an attacker is able to coerce your peer into +only connecting to nodes they control. + +The address manager also understands routability and Tor addresses and tries +hard to only return routable addresses. In addition, it uses the information +provided by the caller about connected, known good, and attempted addresses to +periodically purge peers which no longer appear to be good peers as well as +bias the selection toward known good peers. The general idea is to make a best +effort at only providing usable addresses. +*/ +package addrmgr diff --git a/vendor/github.com/btcsuite/btcd/addrmgr/knownaddress.go b/vendor/github.com/btcsuite/btcd/addrmgr/knownaddress.go new file mode 100644 index 0000000..15469f3 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/addrmgr/knownaddress.go @@ -0,0 +1,102 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package addrmgr + +import ( + "time" + + "github.com/btcsuite/btcd/wire" +) + +// KnownAddress tracks information about a known network address that is used +// to determine how viable an address is. +type KnownAddress struct { + na *wire.NetAddress + srcAddr *wire.NetAddress + attempts int + lastattempt time.Time + lastsuccess time.Time + tried bool + refs int // reference count of new buckets +} + +// NetAddress returns the underlying wire.NetAddress associated with the +// known address. +func (ka *KnownAddress) NetAddress() *wire.NetAddress { + return ka.na +} + +// LastAttempt returns the last time the known address was attempted. +func (ka *KnownAddress) LastAttempt() time.Time { + return ka.lastattempt +} + +// Services returns the services supported by the peer with the known address. +func (ka *KnownAddress) Services() wire.ServiceFlag { + return ka.na.Services +} + +// 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. +func (ka *KnownAddress) chance() float64 { + now := time.Now() + lastAttempt := now.Sub(ka.lastattempt) + + if lastAttempt < 0 { + lastAttempt = 0 + } + + c := 1.0 + + // Very recent attempts are less likely to be retried. + if lastAttempt < 10*time.Minute { + c *= 0.01 + } + + // Failed attempts deprioritise. + for i := ka.attempts; i > 0; i-- { + c /= 1.5 + } + + return c +} + +// isBad returns true if the address in question has not been tried in the last +// minute and meets one of the following criteria: +// 1) It claims to be from the future +// 2) It hasn't been seen in over a month +// 3) It has failed at least three times and never succeeded +// 4) It has failed ten times in the last week +// All addresses that meet these criteria are assumed to be worthless and not +// worth keeping hold of. +func (ka *KnownAddress) isBad() bool { + if ka.lastattempt.After(time.Now().Add(-1 * time.Minute)) { + return false + } + + // From the future? + if ka.na.Timestamp.After(time.Now().Add(10 * time.Minute)) { + return true + } + + // Over a month old? + if ka.na.Timestamp.Before(time.Now().Add(-1 * numMissingDays * time.Hour * 24)) { + return true + } + + // Never succeeded? + if ka.lastsuccess.IsZero() && ka.attempts >= numRetries { + return true + } + + // Hasn't succeeded in too long? + if !ka.lastsuccess.After(time.Now().Add(-1*minBadDays*time.Hour*24)) && + ka.attempts >= maxFailures { + return true + } + + return false +} diff --git a/vendor/github.com/btcsuite/btcd/addrmgr/log.go b/vendor/github.com/btcsuite/btcd/addrmgr/log.go new file mode 100644 index 0000000..b3ebbd1 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/addrmgr/log.go @@ -0,0 +1,32 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package addrmgr + +import ( + "github.com/btcsuite/btclog" +) + +// log is a logger that is initialized with no output filters. This +// means the package will not perform any logging by default until the caller +// requests it. +var log btclog.Logger + +// The default amount of logging is none. +func init() { + DisableLog() +} + +// DisableLog disables all library log output. Logging output is disabled +// by default until either UseLogger or SetLogWriter are called. +func DisableLog() { + log = btclog.Disabled +} + +// UseLogger uses a specified Logger to output package logging info. +// This should be used in preference to SetLogWriter if the caller is also +// using btclog. +func UseLogger(logger btclog.Logger) { + log = logger +} diff --git a/vendor/github.com/btcsuite/btcd/addrmgr/network.go b/vendor/github.com/btcsuite/btcd/addrmgr/network.go new file mode 100644 index 0000000..51bfa3e --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/addrmgr/network.go @@ -0,0 +1,281 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package addrmgr + +import ( + "fmt" + "net" + + "github.com/btcsuite/btcd/wire" +) + +var ( + // rfc1918Nets specifies the IPv4 private address blocks as defined by + // by RFC1918 (10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16). + rfc1918Nets = []net.IPNet{ + ipNet("10.0.0.0", 8, 32), + ipNet("172.16.0.0", 12, 32), + ipNet("192.168.0.0", 16, 32), + } + + // rfc2544Net specifies the the IPv4 block as defined by RFC2544 + // (198.18.0.0/15) + rfc2544Net = ipNet("198.18.0.0", 15, 32) + + // rfc3849Net specifies the IPv6 documentation address block as defined + // by RFC3849 (2001:DB8::/32). + rfc3849Net = ipNet("2001:DB8::", 32, 128) + + // rfc3927Net specifies the IPv4 auto configuration address block as + // defined by RFC3927 (169.254.0.0/16). + rfc3927Net = ipNet("169.254.0.0", 16, 32) + + // rfc3964Net specifies the IPv6 to IPv4 encapsulation address block as + // defined by RFC3964 (2002::/16). + rfc3964Net = ipNet("2002::", 16, 128) + + // rfc4193Net specifies the IPv6 unique local address block as defined + // by RFC4193 (FC00::/7). + rfc4193Net = ipNet("FC00::", 7, 128) + + // rfc4380Net specifies the IPv6 teredo tunneling over UDP address block + // as defined by RFC4380 (2001::/32). + rfc4380Net = ipNet("2001::", 32, 128) + + // rfc4843Net specifies the IPv6 ORCHID address block as defined by + // RFC4843 (2001:10::/28). + rfc4843Net = ipNet("2001:10::", 28, 128) + + // rfc4862Net specifies the IPv6 stateless address autoconfiguration + // address block as defined by RFC4862 (FE80::/64). + rfc4862Net = ipNet("FE80::", 64, 128) + + // rfc5737Net specifies the IPv4 documentation address blocks as defined + // by RFC5737 (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24) + rfc5737Net = []net.IPNet{ + ipNet("192.0.2.0", 24, 32), + ipNet("198.51.100.0", 24, 32), + ipNet("203.0.113.0", 24, 32), + } + + // rfc6052Net specifies the IPv6 well-known prefix address block as + // defined by RFC6052 (64:FF9B::/96). + rfc6052Net = ipNet("64:FF9B::", 96, 128) + + // rfc6145Net specifies the IPv6 to IPv4 translated address range as + // defined by RFC6145 (::FFFF:0:0:0/96). + rfc6145Net = ipNet("::FFFF:0:0:0", 96, 128) + + // rfc6598Net specifies the IPv4 block as defined by RFC6598 (100.64.0.0/10) + rfc6598Net = ipNet("100.64.0.0", 10, 32) + + // onionCatNet defines the IPv6 address block used to support Tor. + // bitcoind encodes a .onion address as a 16 byte number by decoding the + // address prior to the .onion (i.e. the key hash) base32 into a ten + // byte number. It then stores the first 6 bytes of the address as + // 0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43. + // + // This is the same range used by OnionCat, which is part part of the + // RFC4193 unique local IPv6 range. + // + // In summary the format is: + // { magic 6 bytes, 10 bytes base32 decode of key hash } + onionCatNet = ipNet("fd87:d87e:eb43::", 48, 128) + + // zero4Net defines the IPv4 address block for address staring with 0 + // (0.0.0.0/8). + zero4Net = ipNet("0.0.0.0", 8, 32) + + // heNet defines the Hurricane Electric IPv6 address block. + heNet = ipNet("2001:470::", 32, 128) +) + +// ipNet returns a net.IPNet struct given the passed IP address string, number +// of one bits to include at the start of the mask, and the total number of bits +// for the mask. +func ipNet(ip string, ones, bits int) net.IPNet { + return net.IPNet{IP: net.ParseIP(ip), Mask: net.CIDRMask(ones, bits)} +} + +// IsIPv4 returns whether or not the given address is an IPv4 address. +func IsIPv4(na *wire.NetAddress) bool { + return na.IP.To4() != nil +} + +// IsLocal returns whether or not the given address is a local address. +func IsLocal(na *wire.NetAddress) bool { + return na.IP.IsLoopback() || zero4Net.Contains(na.IP) +} + +// IsOnionCatTor returns whether or not the passed address is in the IPv6 range +// used by bitcoin to support Tor (fd87:d87e:eb43::/48). Note that this range +// is the same range used by OnionCat, which is part of the RFC4193 unique local +// IPv6 range. +func IsOnionCatTor(na *wire.NetAddress) bool { + return onionCatNet.Contains(na.IP) +} + +// IsRFC1918 returns whether or not the passed address is part of the IPv4 +// private network address space as defined by RFC1918 (10.0.0.0/8, +// 172.16.0.0/12, or 192.168.0.0/16). +func IsRFC1918(na *wire.NetAddress) bool { + for _, rfc := range rfc1918Nets { + if rfc.Contains(na.IP) { + return true + } + } + return false +} + +// IsRFC2544 returns whether or not the passed address is part of the IPv4 +// address space as defined by RFC2544 (198.18.0.0/15) +func IsRFC2544(na *wire.NetAddress) bool { + return rfc2544Net.Contains(na.IP) +} + +// IsRFC3849 returns whether or not the passed address is part of the IPv6 +// documentation range as defined by RFC3849 (2001:DB8::/32). +func IsRFC3849(na *wire.NetAddress) bool { + return rfc3849Net.Contains(na.IP) +} + +// IsRFC3927 returns whether or not the passed address is part of the IPv4 +// autoconfiguration range as defined by RFC3927 (169.254.0.0/16). +func IsRFC3927(na *wire.NetAddress) bool { + return rfc3927Net.Contains(na.IP) +} + +// IsRFC3964 returns whether or not the passed address is part of the IPv6 to +// IPv4 encapsulation range as defined by RFC3964 (2002::/16). +func IsRFC3964(na *wire.NetAddress) bool { + return rfc3964Net.Contains(na.IP) +} + +// IsRFC4193 returns whether or not the passed address is part of the IPv6 +// unique local range as defined by RFC4193 (FC00::/7). +func IsRFC4193(na *wire.NetAddress) bool { + return rfc4193Net.Contains(na.IP) +} + +// IsRFC4380 returns whether or not the passed address is part of the IPv6 +// teredo tunneling over UDP range as defined by RFC4380 (2001::/32). +func IsRFC4380(na *wire.NetAddress) bool { + return rfc4380Net.Contains(na.IP) +} + +// IsRFC4843 returns whether or not the passed address is part of the IPv6 +// ORCHID range as defined by RFC4843 (2001:10::/28). +func IsRFC4843(na *wire.NetAddress) bool { + return rfc4843Net.Contains(na.IP) +} + +// IsRFC4862 returns whether or not the passed address is part of the IPv6 +// stateless address autoconfiguration range as defined by RFC4862 (FE80::/64). +func IsRFC4862(na *wire.NetAddress) bool { + return rfc4862Net.Contains(na.IP) +} + +// IsRFC5737 returns whether or not the passed address is part of the IPv4 +// documentation address space as defined by RFC5737 (192.0.2.0/24, +// 198.51.100.0/24, 203.0.113.0/24) +func IsRFC5737(na *wire.NetAddress) bool { + for _, rfc := range rfc5737Net { + if rfc.Contains(na.IP) { + return true + } + } + + return false +} + +// IsRFC6052 returns whether or not the passed address is part of the IPv6 +// well-known prefix range as defined by RFC6052 (64:FF9B::/96). +func IsRFC6052(na *wire.NetAddress) bool { + return rfc6052Net.Contains(na.IP) +} + +// IsRFC6145 returns whether or not the passed address is part of the IPv6 to +// IPv4 translated address range as defined by RFC6145 (::FFFF:0:0:0/96). +func IsRFC6145(na *wire.NetAddress) bool { + return rfc6145Net.Contains(na.IP) +} + +// IsRFC6598 returns whether or not the passed address is part of the IPv4 +// shared address space specified by RFC6598 (100.64.0.0/10) +func IsRFC6598(na *wire.NetAddress) bool { + return rfc6598Net.Contains(na.IP) +} + +// IsValid returns whether or not the passed address is valid. The address is +// considered invalid under the following circumstances: +// IPv4: It is either a zero or all bits set address. +// IPv6: It is either a zero or RFC3849 documentation address. +func IsValid(na *wire.NetAddress) bool { + // IsUnspecified returns if address is 0, so only all bits set, and + // RFC3849 need to be explicitly checked. + return na.IP != nil && !(na.IP.IsUnspecified() || + na.IP.Equal(net.IPv4bcast)) +} + +// IsRoutable returns whether or not the passed address is routable over +// the public internet. This is true as long as the address is valid and is not +// in any reserved ranges. +func IsRoutable(na *wire.NetAddress) bool { + return IsValid(na) && !(IsRFC1918(na) || IsRFC2544(na) || + IsRFC3927(na) || IsRFC4862(na) || IsRFC3849(na) || + IsRFC4843(na) || IsRFC5737(na) || IsRFC6598(na) || + IsLocal(na) || (IsRFC4193(na) && !IsOnionCatTor(na))) +} + +// GroupKey returns a string representing the network group an address is part +// of. This is the /16 for IPv4, the /32 (/36 for he.net) for IPv6, the string +// "local" for a local address, the string "tor:key" where key is the /4 of the +// onion address for Tor address, and the string "unroutable" for an unroutable +// address. +func GroupKey(na *wire.NetAddress) string { + if IsLocal(na) { + return "local" + } + if !IsRoutable(na) { + return "unroutable" + } + if IsIPv4(na) { + return na.IP.Mask(net.CIDRMask(16, 32)).String() + } + if IsRFC6145(na) || IsRFC6052(na) { + // last four bytes are the ip address + ip := na.IP[12:16] + return ip.Mask(net.CIDRMask(16, 32)).String() + } + + if IsRFC3964(na) { + ip := na.IP[2:6] + return ip.Mask(net.CIDRMask(16, 32)).String() + + } + if IsRFC4380(na) { + // teredo tunnels have the last 4 bytes as the v4 address XOR + // 0xff. + ip := net.IP(make([]byte, 4)) + for i, byte := range na.IP[12:16] { + ip[i] = byte ^ 0xff + } + return ip.Mask(net.CIDRMask(16, 32)).String() + } + if IsOnionCatTor(na) { + // group is keyed off the first 4 bits of the actual onion key. + return fmt.Sprintf("tor:%d", na.IP[6]&((1<<4)-1)) + } + + // OK, so now we know ourselves to be a IPv6 address. + // bitcoind uses /32 for everything, except for Hurricane Electric's + // (he.net) IP range, which it uses /36 for. + bits := 32 + if heNet.Contains(na.IP) { + bits = 36 + } + + return na.IP.Mask(net.CIDRMask(bits, 128)).String() +} diff --git a/vendor/github.com/btcsuite/btcd/addrmgr/test_coverage.txt b/vendor/github.com/btcsuite/btcd/addrmgr/test_coverage.txt new file mode 100644 index 0000000..c67e0f6 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/addrmgr/test_coverage.txt @@ -0,0 +1,62 @@ + +github.com/conformal/btcd/addrmgr/network.go GroupKey 100.00% (23/23) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.reset 100.00% (6/6) +github.com/conformal/btcd/addrmgr/network.go IsRFC5737 100.00% (4/4) +github.com/conformal/btcd/addrmgr/network.go IsRFC1918 100.00% (4/4) +github.com/conformal/btcd/addrmgr/addrmanager.go New 100.00% (3/3) +github.com/conformal/btcd/addrmgr/addrmanager.go NetAddressKey 100.00% (2/2) +github.com/conformal/btcd/addrmgr/network.go IsRFC4862 100.00% (1/1) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.numAddresses 100.00% (1/1) +github.com/conformal/btcd/addrmgr/log.go init 100.00% (1/1) +github.com/conformal/btcd/addrmgr/log.go DisableLog 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go ipNet 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsIPv4 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsLocal 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsOnionCatTor 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC2544 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC3849 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC3927 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC3964 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC4193 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC4380 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC4843 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC6052 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC6145 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRFC6598 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsValid 100.00% (1/1) +github.com/conformal/btcd/addrmgr/network.go IsRoutable 100.00% (1/1) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.GetBestLocalAddress 94.74% (18/19) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.AddLocalAddress 90.91% (10/11) +github.com/conformal/btcd/addrmgr/addrmanager.go getReachabilityFrom 51.52% (17/33) +github.com/conformal/btcd/addrmgr/addrmanager.go ipString 50.00% (2/4) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.GetAddress 9.30% (4/43) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.deserializePeers 0.00% (0/50) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.Good 0.00% (0/44) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.savePeers 0.00% (0/39) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.updateAddress 0.00% (0/30) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.expireNew 0.00% (0/22) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.AddressCache 0.00% (0/16) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.HostToNetAddress 0.00% (0/15) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.getNewBucket 0.00% (0/15) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.AddAddressByIP 0.00% (0/14) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.getTriedBucket 0.00% (0/14) +github.com/conformal/btcd/addrmgr/knownaddress.go knownAddress.chance 0.00% (0/13) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.loadPeers 0.00% (0/11) +github.com/conformal/btcd/addrmgr/knownaddress.go knownAddress.isBad 0.00% (0/11) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.Connected 0.00% (0/10) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.addressHandler 0.00% (0/9) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.pickTried 0.00% (0/8) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.DeserializeNetAddress 0.00% (0/7) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.Stop 0.00% (0/7) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.Attempt 0.00% (0/7) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.Start 0.00% (0/6) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.AddAddresses 0.00% (0/4) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.NeedMoreAddresses 0.00% (0/3) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.NumAddresses 0.00% (0/3) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.AddAddress 0.00% (0/3) +github.com/conformal/btcd/addrmgr/knownaddress.go knownAddress.LastAttempt 0.00% (0/1) +github.com/conformal/btcd/addrmgr/knownaddress.go knownAddress.NetAddress 0.00% (0/1) +github.com/conformal/btcd/addrmgr/addrmanager.go AddrManager.find 0.00% (0/1) +github.com/conformal/btcd/addrmgr/log.go UseLogger 0.00% (0/1) +github.com/conformal/btcd/addrmgr --------------------------------- 21.04% (113/537) + diff --git a/vendor/github.com/btcsuite/btcd/blockchain/README.md b/vendor/github.com/btcsuite/btcd/blockchain/README.md new file mode 100644 index 0000000..de5611b --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/README.md @@ -0,0 +1,103 @@ +blockchain +========== + +[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)](https://travis-ci.org/btcsuite/btcd) +[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) +[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/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 + +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 + +## Examples + +* [ProcessBlock Example](http://godoc.org/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](http://godoc.org/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](http://godoc.org/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. diff --git a/vendor/github.com/btcsuite/btcd/blockchain/accept.go b/vendor/github.com/btcsuite/btcd/blockchain/accept.go new file mode 100644 index 0000000..f85d655 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/accept.go @@ -0,0 +1,92 @@ +// Copyright (c) 2013-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 ( + "fmt" + + "github.com/btcsuite/btcd/database" + "github.com/btcsuite/btcutil" +) + +// maybeAcceptBlock potentially accepts a block into the block chain and, if +// accepted, returns whether or not it is on the main chain. It performs +// several validation checks which depend on its position within the block chain +// before adding it. The block is expected to have already gone through +// ProcessBlock before calling this function with it. +// +// The flags are also passed to checkBlockContext and connectBestChain. See +// their documentation for how the flags modify their behavior. +// +// This function MUST be called with the chain state lock held (for writes). +func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) (bool, error) { + // The height of this block is one more than the referenced previous + // block. + prevHash := &block.MsgBlock().Header.PrevBlock + prevNode := b.index.LookupNode(prevHash) + if prevNode == nil { + str := fmt.Sprintf("previous block %s is unknown", prevHash) + return false, ruleError(ErrPreviousBlockUnknown, str) + } else if b.index.NodeStatus(prevNode).KnownInvalid() { + str := fmt.Sprintf("previous block %s is known to be invalid", prevHash) + return false, ruleError(ErrInvalidAncestorBlock, str) + } + + blockHeight := prevNode.height + 1 + block.SetHeight(blockHeight) + + // The block must pass all of the validation rules which depend on the + // position of the block within the block chain. + err := b.checkBlockContext(block, prevNode, flags) + if err != nil { + return false, err + } + + // Insert the block into the database if it's not already there. Even + // though it is possible the block will ultimately fail to connect, it + // has already passed all proof-of-work and validity tests which means + // it would be prohibitively expensive for an attacker to fill up the + // disk with a bunch of blocks that fail to connect. This is necessary + // since it allows block download to be decoupled from the much more + // expensive connection logic. It also has some other nice properties + // such as making blocks that never become part of the main chain or + // blocks that fail to connect available for further analysis. + err = b.db.Update(func(dbTx database.Tx) error { + return dbStoreBlock(dbTx, block) + }) + if err != nil { + return false, err + } + + // Create a new block node for the block and add it to the node index. Even + // if the block ultimately gets connected to the main chain, it starts out + // on a side chain. + blockHeader := &block.MsgBlock().Header + newNode := newBlockNode(blockHeader, prevNode) + newNode.status = statusDataStored + + b.index.AddNode(newNode) + err = b.index.flushToDB() + if err != nil { + return false, err + } + + // Connect the passed block to the chain while respecting proper chain + // selection according to the chain with the most proof of work. This + // also handles validation of the transaction scripts. + isMainChain, err := b.connectBestChain(newNode, block, flags) + if err != nil { + return false, err + } + + // 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.chainLock.Unlock() + b.sendNotification(NTBlockAccepted, block) + b.chainLock.Lock() + + return isMainChain, nil +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/blockindex.go b/vendor/github.com/btcsuite/btcd/blockchain/blockindex.go new file mode 100644 index 0000000..2ff2fa2 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/blockindex.go @@ -0,0 +1,348 @@ +// Copyright (c) 2015-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 ( + "math/big" + "sort" + "sync" + "time" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/database" + "github.com/btcsuite/btcd/wire" +) + +// blockStatus is a bit field representing the validation state of the block. +type blockStatus byte + +const ( + // statusDataStored indicates that the block's payload is stored on disk. + statusDataStored blockStatus = 1 << iota + + // statusValid indicates that the block has been fully validated. + statusValid + + // statusValidateFailed indicates that the block has failed validation. + statusValidateFailed + + // statusInvalidAncestor indicates that one of the block's ancestors has + // has failed validation, thus the block is also invalid. + statusInvalidAncestor + + // statusNone indicates that the block has no validation state flags set. + // + // NOTE: This must be defined last in order to avoid influencing iota. + statusNone blockStatus = 0 +) + +// HaveData returns whether the full block data is stored in the database. This +// will return false for a block node where only the header is downloaded or +// kept. +func (status blockStatus) HaveData() bool { + return status&statusDataStored != 0 +} + +// KnownValid returns whether the block is known to be valid. This will return +// false for a valid block that has not been fully validated yet. +func (status blockStatus) KnownValid() bool { + return status&statusValid != 0 +} + +// KnownInvalid returns whether the block is known to be invalid. This may be +// because the block itself failed validation or any of its ancestors is +// invalid. This will return false for invalid blocks that have not been proven +// invalid yet. +func (status blockStatus) KnownInvalid() bool { + return status&(statusValidateFailed|statusInvalidAncestor) != 0 +} + +// blockNode represents a block within the block chain and is primarily used to +// aid in selecting the best chain to be the main chain. The main chain is +// stored into the block database. +type blockNode struct { + // NOTE: Additions, deletions, or modifications to the order of the + // definitions in this struct should not be changed without considering + // how it affects alignment on 64-bit platforms. The current order is + // specifically crafted to result in minimal padding. There will be + // hundreds of thousands of these in memory, so a few extra bytes of + // padding adds up. + + // parent is the parent block for this node. + parent *blockNode + + // hash is the double sha 256 of the block. + hash chainhash.Hash + + // workSum is the total amount of work in the chain up to and including + // this node. + workSum *big.Int + + // height is the position in the block chain. + height int32 + + // Some fields from block headers to aid in best chain selection and + // reconstructing headers from memory. These must be treated as + // immutable and are intentionally ordered to avoid padding on 64-bit + // platforms. + version int32 + bits uint32 + nonce uint32 + timestamp int64 + merkleRoot 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 + // only be accessed using the concurrent-safe NodeStatus method on + // blockIndex once the node has been added to the global index. + status blockStatus +} + +// initBlockNode initializes a block node from the given header and parent node, +// calculating the height and workSum from the respective fields on the parent. +// This function is NOT safe for concurrent access. It must only be called when +// initially creating a node. +func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *blockNode) { + *node = blockNode{ + hash: blockHeader.BlockHash(), + workSum: CalcWork(blockHeader.Bits), + version: blockHeader.Version, + bits: blockHeader.Bits, + nonce: blockHeader.Nonce, + timestamp: blockHeader.Timestamp.Unix(), + merkleRoot: blockHeader.MerkleRoot, + } + if parent != nil { + node.parent = parent + node.height = parent.height + 1 + node.workSum = node.workSum.Add(parent.workSum, node.workSum) + } +} + +// newBlockNode returns a new block node for the given block header and parent +// node, calculating the height and workSum from the respective fields on the +// parent. This function is NOT safe for concurrent access. +func newBlockNode(blockHeader *wire.BlockHeader, parent *blockNode) *blockNode { + var node blockNode + initBlockNode(&node, blockHeader, parent) + return &node +} + +// Header constructs a block header from the node and returns it. +// +// This function is safe for concurrent access. +func (node *blockNode) Header() wire.BlockHeader { + // No lock is needed because all accessed fields are immutable. + prevHash := &zeroHash + if node.parent != nil { + prevHash = &node.parent.hash + } + return wire.BlockHeader{ + Version: node.version, + PrevBlock: *prevHash, + MerkleRoot: node.merkleRoot, + Timestamp: time.Unix(node.timestamp, 0), + Bits: node.bits, + Nonce: node.nonce, + } +} + +// Ancestor returns the ancestor block node at the provided height by following +// the chain backwards from this node. The returned block will be nil when a +// height is requested that is after the height of the passed node or is less +// than zero. +// +// This function is safe for concurrent access. +func (node *blockNode) Ancestor(height int32) *blockNode { + if height < 0 || height > node.height { + return nil + } + + n := node + for ; n != nil && n.height != height; n = n.parent { + // Intentionally left blank + } + + return n +} + +// RelativeAncestor returns the ancestor block node a relative 'distance' blocks +// before this node. This is equivalent to calling Ancestor with the node's +// height minus provided distance. +// +// This function is safe for concurrent access. +func (node *blockNode) RelativeAncestor(distance int32) *blockNode { + return node.Ancestor(node.height - distance) +} + +// CalcPastMedianTime calculates the median time of the previous few blocks +// prior to, and including, the block node. +// +// This function is safe for concurrent access. +func (node *blockNode) CalcPastMedianTime() time.Time { + // Create a slice of the previous few block timestamps used to calculate + // the median per the number defined by the constant medianTimeBlocks. + timestamps := make([]int64, medianTimeBlocks) + numNodes := 0 + iterNode := node + for i := 0; i < medianTimeBlocks && iterNode != nil; i++ { + timestamps[i] = iterNode.timestamp + numNodes++ + + iterNode = iterNode.parent + } + + // Prune the slice to the actual number of available timestamps which + // will be fewer than desired near the beginning of the block chain + // and sort them. + timestamps = timestamps[:numNodes] + sort.Sort(timeSorter(timestamps)) + + // NOTE: The consensus rules incorrectly calculate the median for even + // numbers of blocks. A true median averages the middle two elements + // for a set with an even number of elements in it. Since the constant + // for the previous number of blocks to be used is odd, this is only an + // issue for a few blocks near the beginning of the chain. I suspect + // this is an optimization even though the result is slightly wrong for + // a few of the first blocks since after the first few blocks, there + // will always be an odd number of blocks in the set per the constant. + // + // This code follows suit to ensure the same rules are used, however, be + // aware that should the medianTimeBlocks constant ever be changed to an + // even number, this code will be wrong. + medianTimestamp := timestamps[numNodes/2] + return time.Unix(medianTimestamp, 0) +} + +// blockIndex provides facilities for keeping track of an in-memory index of the +// block chain. Although the name block chain suggests a single chain of +// blocks, it is actually a tree-shaped structure where any node can have +// multiple children. However, there can only be one active branch which does +// indeed form a chain from the tip all the way back to the genesis block. +type blockIndex struct { + // The following fields are set when the instance is created and can't + // be changed afterwards, so there is no need to protect them with a + // separate mutex. + db database.DB + chainParams *chaincfg.Params + + sync.RWMutex + index map[chainhash.Hash]*blockNode + dirty map[*blockNode]struct{} +} + +// newBlockIndex returns a new empty instance of a block index. The index will +// be dynamically populated as block nodes are loaded from the database and +// manually added. +func newBlockIndex(db database.DB, chainParams *chaincfg.Params) *blockIndex { + return &blockIndex{ + db: db, + chainParams: chainParams, + index: make(map[chainhash.Hash]*blockNode), + dirty: make(map[*blockNode]struct{}), + } +} + +// HaveBlock returns whether or not the block index contains the provided hash. +// +// This function is safe for concurrent access. +func (bi *blockIndex) HaveBlock(hash *chainhash.Hash) bool { + bi.RLock() + _, hasBlock := bi.index[*hash] + bi.RUnlock() + return hasBlock +} + +// LookupNode returns the block node identified by the provided hash. It will +// return nil if there is no entry for the hash. +// +// This function is safe for concurrent access. +func (bi *blockIndex) LookupNode(hash *chainhash.Hash) *blockNode { + bi.RLock() + node := bi.index[*hash] + bi.RUnlock() + return node +} + +// AddNode adds the provided node to the block index and marks it as dirty. +// Duplicate entries are not checked so it is up to caller to avoid adding them. +// +// This function is safe for concurrent access. +func (bi *blockIndex) AddNode(node *blockNode) { + bi.Lock() + bi.addNode(node) + bi.dirty[node] = struct{}{} + bi.Unlock() +} + +// addNode adds the provided node to the block index, but does not mark it as +// dirty. This can be used while initializing the block index. +// +// This function is NOT safe for concurrent access. +func (bi *blockIndex) addNode(node *blockNode) { + bi.index[node.hash] = node +} + +// NodeStatus provides concurrent-safe access to the status field of a node. +// +// This function is safe for concurrent access. +func (bi *blockIndex) NodeStatus(node *blockNode) blockStatus { + bi.RLock() + status := node.status + bi.RUnlock() + return status +} + +// SetStatusFlags flips the provided status flags on the block node to on, +// regardless of whether they were on or off previously. This does not unset any +// flags currently on. +// +// This function is safe for concurrent access. +func (bi *blockIndex) SetStatusFlags(node *blockNode, flags blockStatus) { + bi.Lock() + node.status |= flags + bi.dirty[node] = struct{}{} + bi.Unlock() +} + +// UnsetStatusFlags flips the provided status flags on the block node to off, +// regardless of whether they were on or off previously. +// +// This function is safe for concurrent access. +func (bi *blockIndex) UnsetStatusFlags(node *blockNode, flags blockStatus) { + bi.Lock() + node.status &^= flags + bi.dirty[node] = struct{}{} + bi.Unlock() +} + +// flushToDB writes all dirty block nodes to the database. If all writes +// succeed, this clears the dirty set. +func (bi *blockIndex) flushToDB() error { + bi.Lock() + if len(bi.dirty) == 0 { + bi.Unlock() + return nil + } + + err := bi.db.Update(func(dbTx database.Tx) error { + for node := range bi.dirty { + err := dbStoreBlockNode(dbTx, node) + if err != nil { + return err + } + } + return nil + }) + + // If write was successful, clear the dirty set. + if err == nil { + bi.dirty = make(map[*blockNode]struct{}) + } + + bi.Unlock() + return err +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/chain.go b/vendor/github.com/btcsuite/btcd/blockchain/chain.go new file mode 100644 index 0000000..71c1b2e --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/chain.go @@ -0,0 +1,1803 @@ +// Copyright (c) 2013-2018 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package blockchain + +import ( + "container/list" + "fmt" + "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" +) + +const ( + // maxOrphanBlocks is the maximum number of orphan blocks that can be + // queued. + maxOrphanBlocks = 100 +) + +// BlockLocator is used to help locate a specific block. The algorithm for +// building the block locator is to add the hashes in reverse order until +// the genesis block is reached. In order to keep the list of locator hashes +// to a reasonable number of entries, first the most recent previous 12 block +// hashes are added, then the step is doubled each loop iteration to +// exponentially decrease the number of hashes as a function of the distance +// 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 +// +// 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] +type BlockLocator []*chainhash.Hash + +// orphanBlock represents a block that we don't yet have the parent for. It +// is a normal block plus an expiration time to prevent caching the orphan +// forever. +type orphanBlock struct { + block *btcutil.Block + expiration time.Time +} + +// BestState houses information about the current best block and other info +// related to the state of the main chain as it exists from the point of view of +// the current best block. +// +// The BestSnapshot method can be used to obtain access to this information +// in a concurrent safe manner and the data will not be changed out from under +// the caller when chain state changes occur as the function name implies. +// However, the returned snapshot must be treated as immutable since it is +// shared by all callers. +type BestState struct { + Hash chainhash.Hash // The hash of the block. + Height int32 // The height of the block. + Bits uint32 // The difficulty bits of the block. + BlockSize uint64 // The size of the block. + BlockWeight uint64 // The weight of the block. + NumTxns uint64 // The number of txns in the block. + TotalTxns uint64 // The total number of txns in the chain. + MedianTime time.Time // Median time as per CalcPastMedianTime. +} + +// newBestState returns a new best stats instance for the given parameters. +func newBestState(node *blockNode, blockSize, blockWeight, numTxns, + totalTxns uint64, medianTime time.Time) *BestState { + + return &BestState{ + Hash: node.hash, + Height: node.height, + Bits: node.bits, + BlockSize: blockSize, + BlockWeight: blockWeight, + NumTxns: numTxns, + TotalTxns: totalTxns, + MedianTime: medianTime, + } +} + +// BlockChain provides functions for working with the bitcoin block chain. +// It includes functionality such as rejecting duplicate blocks, ensuring blocks +// follow all rules, orphan handling, checkpoint handling, and best chain +// selection with reorganization. +type BlockChain struct { + // The following fields are set when the instance is created and can't + // be changed afterwards, so there is no need to protect them with a + // separate mutex. + checkpoints []chaincfg.Checkpoint + checkpointsByHeight map[int32]*chaincfg.Checkpoint + db database.DB + chainParams *chaincfg.Params + timeSource MedianTimeSource + sigCache *txscript.SigCache + indexManager IndexManager + hashCache *txscript.HashCache + + // The following fields are calculated based upon the provided chain + // parameters. They are also set when the instance is created and + // can't be changed afterwards, so there is no need to protect them with + // a separate mutex. + minRetargetTimespan int64 // target timespan / adjustment factor + maxRetargetTimespan int64 // target timespan * adjustment factor + blocksPerRetarget int32 // target timespan / target time per block + + // chainLock protects concurrent access to the vast majority of the + // fields in this struct below this point. + chainLock sync.RWMutex + + // 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. + // + // index houses the entire block index in memory. The block index is + // a tree-shaped structure. + // + // bestChain tracks the current active chain by making use of an + // efficient chain view into the block index. + index *blockIndex + bestChain *chainView + + // These fields are related to handling of orphan blocks. They are + // protected by a combination of the chain lock and the orphan lock. + orphanLock sync.RWMutex + orphans map[chainhash.Hash]*orphanBlock + prevOrphans map[chainhash.Hash][]*orphanBlock + oldestOrphan *orphanBlock + + // These fields are related to checkpoint handling. They are protected + // by the chain lock. + nextCheckpoint *chaincfg.Checkpoint + checkpointNode *blockNode + + // The state is used as a fairly efficient way to cache information + // about the current best chain state that is returned to callers when + // requested. It operates on the principle of MVCC such that any time a + // new block becomes the best block, the state pointer is replaced with + // a new struct and the old state is left untouched. In this way, + // multiple callers can be pointing to different best chain states. + // This is acceptable for most callers because the state is only being + // queried at a specific point in time. + // + // In addition, some of the fields are stored in the database so the + // chain state can be quickly reconstructed on load. + stateLock sync.RWMutex + stateSnapshot *BestState + + // The following caches are used to efficiently keep track of the + // current deployment threshold state of each rule change deployment. + // + // This information is stored in the database so it can be quickly + // reconstructed on load. + // + // warningCaches caches the current deployment threshold state for blocks + // in each of the **possible** deployments. This is used in order to + // detect when new unrecognized rule changes are being voted on and/or + // have been activated such as will be the case when older versions of + // the software are being used + // + // deploymentCaches caches the current deployment threshold state for + // blocks in each of the actively defined deployments. + warningCaches []thresholdStateCache + deploymentCaches []thresholdStateCache + + // The following fields are used to determine if certain warnings have + // already been shown. + // + // unknownRulesWarned refers to warnings due to unknown rules being + // activated. + // + // unknownVersionsWarned refers to warnings due to unknown versions + // being mined. + unknownRulesWarned bool + unknownVersionsWarned bool + + // The notifications field stores a slice of callbacks to be executed on + // certain blockchain events. + notificationsLock sync.RWMutex + notifications []NotificationCallback +} + +// HaveBlock returns whether or not the chain instance has the block represented +// by the passed hash. This includes checking the various places a block can +// be like part of the main chain, on a side chain, or in the orphan pool. +// +// This function is safe for concurrent access. +func (b *BlockChain) HaveBlock(hash *chainhash.Hash) (bool, error) { + exists, err := b.blockExists(hash) + if err != nil { + return false, err + } + return exists || b.IsKnownOrphan(hash), nil +} + +// 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 +// way to test if a block is an orphan block. A full block (as opposed to just +// its hash) must be passed to ProcessBlock for that purpose. However, calling +// ProcessBlock with an orphan that already exists results in an error, so this +// function provides a mechanism for a caller to intelligently detect *recent* +// duplicate orphans and react accordingly. +// +// This function is safe for concurrent access. +func (b *BlockChain) IsKnownOrphan(hash *chainhash.Hash) bool { + // Protect concurrent access. Using a read lock only so multiple + // readers can query without blocking each other. + b.orphanLock.RLock() + _, exists := b.orphans[*hash] + b.orphanLock.RUnlock() + + return exists +} + +// GetOrphanRoot returns the head of the chain for the provided hash from the +// map of orphan blocks. +// +// This function is safe for concurrent access. +func (b *BlockChain) GetOrphanRoot(hash *chainhash.Hash) *chainhash.Hash { + // Protect concurrent access. Using a read lock only so multiple + // readers can query without blocking each other. + b.orphanLock.RLock() + defer b.orphanLock.RUnlock() + + // Keep looping while the parent of each orphaned block is + // known and is an orphan itself. + orphanRoot := hash + prevHash := hash + for { + orphan, exists := b.orphans[*prevHash] + if !exists { + break + } + orphanRoot = prevHash + prevHash = &orphan.block.MsgBlock().Header.PrevBlock + } + + return orphanRoot +} + +// removeOrphanBlock removes the passed orphan block from the orphan pool and +// previous orphan index. +func (b *BlockChain) removeOrphanBlock(orphan *orphanBlock) { + // Protect concurrent access. + b.orphanLock.Lock() + defer b.orphanLock.Unlock() + + // Remove the orphan block from the orphan pool. + orphanHash := orphan.block.Hash() + delete(b.orphans, *orphanHash) + + // Remove the reference from the previous orphan index too. An indexing + // for loop is intentionally used over a range here as range does not + // reevaluate the slice on each iteration nor does it adjust the index + // for the modified slice. + prevHash := &orphan.block.MsgBlock().Header.PrevBlock + orphans := b.prevOrphans[*prevHash] + for i := 0; i < len(orphans); i++ { + hash := orphans[i].block.Hash() + if hash.IsEqual(orphanHash) { + copy(orphans[i:], orphans[i+1:]) + orphans[len(orphans)-1] = nil + orphans = orphans[:len(orphans)-1] + i-- + } + } + b.prevOrphans[*prevHash] = orphans + + // Remove the map entry altogether if there are no longer any orphans + // which depend on the parent hash. + if len(b.prevOrphans[*prevHash]) == 0 { + delete(b.prevOrphans, *prevHash) + } +} + +// addOrphanBlock adds the passed block (which is already determined to be +// an orphan prior calling this function) to the orphan pool. It lazily cleans +// up any expired blocks so a separate cleanup poller doesn't need to be run. +// It also imposes a maximum limit on the number of outstanding orphan +// blocks and will remove the oldest received orphan block if the limit is +// exceeded. +func (b *BlockChain) addOrphanBlock(block *btcutil.Block) { + // Remove expired orphan blocks. + for _, oBlock := range b.orphans { + if time.Now().After(oBlock.expiration) { + b.removeOrphanBlock(oBlock) + continue + } + + // Update the oldest orphan block pointer so it can be discarded + // in case the orphan pool fills up. + if b.oldestOrphan == nil || oBlock.expiration.Before(b.oldestOrphan.expiration) { + b.oldestOrphan = oBlock + } + } + + // Limit orphan blocks to prevent memory exhaustion. + if len(b.orphans)+1 > maxOrphanBlocks { + // Remove the oldest orphan to make room for the new one. + b.removeOrphanBlock(b.oldestOrphan) + b.oldestOrphan = nil + } + + // Protect concurrent access. This is intentionally done here instead + // of near the top since removeOrphanBlock does its own locking and + // the range iterator is not invalidated by removing map entries. + b.orphanLock.Lock() + defer b.orphanLock.Unlock() + + // Insert the block into the orphan map with an expiration time + // 1 hour from now. + expiration := time.Now().Add(time.Hour) + oBlock := &orphanBlock{ + block: block, + expiration: expiration, + } + b.orphans[*block.Hash()] = oBlock + + // Add to previous hash lookup index for faster dependency lookups. + prevHash := &block.MsgBlock().Header.PrevBlock + b.prevOrphans[*prevHash] = append(b.prevOrphans[*prevHash], oBlock) +} + +// SequenceLock represents the converted relative lock-time in seconds, and +// absolute block-height for a transaction input's relative lock-times. +// According to SequenceLock, after the referenced input has been confirmed +// within a block, a transaction spending that input can be included into a +// block either after 'seconds' (according to past median time), or once the +// 'BlockHeight' has been reached. +type SequenceLock struct { + Seconds int64 + BlockHeight int32 +} + +// CalcSequenceLock computes a relative lock-time SequenceLock for the passed +// transaction using the passed UtxoViewpoint to obtain the past median time +// for blocks in which the referenced inputs of the transactions were included +// within. The generated SequenceLock lock can be used in conjunction with a +// block height, and adjusted median block time to determine if all the inputs +// referenced within a transaction have reached sufficient maturity allowing +// the candidate transaction to be included in a block. +// +// This function is safe for concurrent access. +func (b *BlockChain) CalcSequenceLock(tx *btcutil.Tx, utxoView *UtxoViewpoint, mempool bool) (*SequenceLock, error) { + b.chainLock.Lock() + defer b.chainLock.Unlock() + + return b.calcSequenceLock(b.bestChain.Tip(), tx, utxoView, mempool) +} + +// calcSequenceLock computes the relative lock-times for the passed +// transaction. See the exported version, CalcSequenceLock for further details. +// +// This function MUST be called with the chain state lock held (for writes). +func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView *UtxoViewpoint, mempool bool) (*SequenceLock, error) { + // A value of -1 for each relative lock type represents a relative time + // lock value that will allow a transaction to be included in a block + // at any given height or time. This value is returned as the relative + // lock time in the case that BIP 68 is disabled, or has not yet been + // activated. + sequenceLock := &SequenceLock{Seconds: -1, BlockHeight: -1} + + // The sequence locks semantics are always active for transactions + // within the mempool. + csvSoftforkActive := mempool + + // If we're performing block validation, then we need to query the BIP9 + // state. + if !csvSoftforkActive { + // Obtain the latest BIP9 version bits state for the + // CSV-package soft-fork deployment. The adherence of sequence + // locks depends on the current soft-fork state. + csvState, err := b.deploymentState(node.parent, chaincfg.DeploymentCSV) + if err != nil { + return nil, err + } + csvSoftforkActive = csvState == ThresholdActive + } + + // If the transaction's version is less than 2, and BIP 68 has not yet + // been activated then sequence locks are disabled. Additionally, + // sequence locks don't apply to coinbase transactions Therefore, we + // return sequence lock values of -1 indicating that this transaction + // can be included within a block at any given height or time. + mTx := tx.MsgTx() + sequenceLockActive := mTx.Version >= 2 && csvSoftforkActive + if !sequenceLockActive || IsCoinBase(tx) { + return sequenceLock, nil + } + + // Grab the next height from the PoV of the passed blockNode to use for + // inputs present in the mempool. + nextHeight := node.height + 1 + + for txInIndex, txIn := range mTx.TxIn { + utxo := utxoView.LookupEntry(txIn.PreviousOutPoint) + if utxo == nil { + str := fmt.Sprintf("output %v referenced from "+ + "transaction %s:%d either does not exist or "+ + "has already been spent", txIn.PreviousOutPoint, + tx.Hash(), txInIndex) + return sequenceLock, ruleError(ErrMissingTxOut, str) + } + + // If the input height is set to the mempool height, then we + // assume the transaction makes it into the next block when + // evaluating its sequence blocks. + inputHeight := utxo.BlockHeight() + if inputHeight == 0x7fffffff { + inputHeight = nextHeight + } + + // Given a sequence number, we apply the relative time lock + // mask in order to obtain the time lock delta required before + // this input can be spent. + sequenceNum := txIn.Sequence + relativeLock := int64(sequenceNum & wire.SequenceLockTimeMask) + + switch { + // Relative time locks are disabled for this input, so we can + // skip any further calculation. + case sequenceNum&wire.SequenceLockTimeDisabled == wire.SequenceLockTimeDisabled: + continue + case sequenceNum&wire.SequenceLockTimeIsSeconds == wire.SequenceLockTimeIsSeconds: + // This input requires a relative time lock expressed + // in seconds before it can be spent. Therefore, we + // need to query for the block prior to the one in + // which this input was included within so we can + // compute the past median time for the block prior to + // the one which included this referenced output. + prevInputHeight := inputHeight - 1 + if prevInputHeight < 0 { + prevInputHeight = 0 + } + blockNode := node.Ancestor(prevInputHeight) + medianTime := blockNode.CalcPastMedianTime() + + // Time based relative time-locks as defined by BIP 68 + // have a time granularity of RelativeLockSeconds, so + // we shift left by this amount to convert to the + // proper relative time-lock. We also subtract one from + // the relative lock to maintain the original lockTime + // semantics. + timeLockSeconds := (relativeLock << wire.SequenceLockTimeGranularity) - 1 + timeLock := medianTime.Unix() + timeLockSeconds + if timeLock > sequenceLock.Seconds { + sequenceLock.Seconds = timeLock + } + default: + // The relative lock-time for this input is expressed + // in blocks so we calculate the relative offset from + // the input's height as its converted absolute + // lock-time. We subtract one from the relative lock in + // order to maintain the original lockTime semantics. + blockHeight := inputHeight + int32(relativeLock-1) + if blockHeight > sequenceLock.BlockHeight { + sequenceLock.BlockHeight = blockHeight + } + } + } + + return sequenceLock, nil +} + +// 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) +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. + if !isSeconds { + return locktime + } + + // Set the 22nd bit which indicates the lock time is in seconds, then + // shift the locktime over by 9 since the time granularity is in + // 512-second intervals (2^9). This results in a max lock-time of + // 33,553,920 seconds, or 1.1 years. + return wire.SequenceLockTimeIsSeconds | + locktime>>wire.SequenceLockTimeGranularity +} + +// getReorganizeNodes finds the fork point between the main chain and the passed +// node and returns a list of block nodes that would need to be detached from +// the main chain and a list of block nodes that would need to be attached to +// the fork point (which will be the end of the main chain after detaching the +// returned list of block nodes) in order to reorganize the chain such that the +// passed node is the new end of the main chain. The lists will be empty if the +// passed node is not on a side chain. +// +// This function may modify node statuses in the block index without flushing. +// +// This function MUST be called with the chain state lock held (for reads). +func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List) { + attachNodes := list.New() + detachNodes := list.New() + + // Do not reorganize to a known invalid chain. Ancestors deeper than the + // direct parent are checked below but this is a quick check before doing + // more unnecessary work. + if b.index.NodeStatus(node.parent).KnownInvalid() { + b.index.SetStatusFlags(node, statusInvalidAncestor) + return detachNodes, attachNodes + } + + // Find the fork point (if any) adding each block to the list of nodes + // to attach to the main tree. Push them onto the list in reverse order + // so they are attached in the appropriate order when iterating the list + // later. + forkNode := b.bestChain.FindFork(node) + invalidChain := false + for n := node; n != nil && n != forkNode; n = n.parent { + if b.index.NodeStatus(n).KnownInvalid() { + invalidChain = true + break + } + attachNodes.PushFront(n) + } + + // If any of the node's ancestors are invalid, unwind attachNodes, marking + // each one as invalid for future reference. + if invalidChain { + var next *list.Element + for e := attachNodes.Front(); e != nil; e = next { + next = e.Next() + n := attachNodes.Remove(e).(*blockNode) + b.index.SetStatusFlags(n, statusInvalidAncestor) + } + return detachNodes, attachNodes + } + + // Start from the end of the main chain and work backwards until the + // common ancestor adding each block to the list of nodes to detach from + // the main chain. + for n := b.bestChain.Tip(); n != nil && n != forkNode; n = n.parent { + detachNodes.PushBack(n) + } + + return detachNodes, attachNodes +} + +// connectBlock handles connecting the passed node/block to the end of the main +// (best) chain. +// +// This passed utxo view must have all referenced txos the block spends marked +// as spent and all of the new txos the block creates added to it. In addition, +// the passed stxos slice must be populated with all of the information for the +// spent txos. This approach is used because the connection validation that +// must happen prior to calling this function requires the same details, so +// it would be inefficient to repeat it. +// +// This function MUST be called with the chain state lock held (for writes). +func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block, + view *UtxoViewpoint, stxos []SpentTxOut) error { + + // Make sure it's extending the end of the best chain. + prevHash := &block.MsgBlock().Header.PrevBlock + if !prevHash.IsEqual(&b.bestChain.Tip().hash) { + return AssertError("connectBlock must be called with a block " + + "that extends the main chain") + } + + // Sanity check the correct number of stxos are provided. + if len(stxos) != countSpentOutputs(block) { + return AssertError("connectBlock called with inconsistent " + + "spent transaction out information") + } + + // No warnings about unknown rules or versions until the chain is + // current. + if b.isCurrent() { + // Warn if any unknown new rules are either about to activate or + // have already been activated. + if err := b.warnUnknownRuleActivations(node); err != nil { + return err + } + + // Warn if a high enough percentage of the last blocks have + // unexpected versions. + if err := b.warnUnknownVersions(node); err != nil { + return err + } + } + + // Write any block status changes to DB before updating best state. + err := b.index.flushToDB() + if err != nil { + return err + } + + // Generate a new best state snapshot that will be used to update the + // database and later memory if all database updates are successful. + b.stateLock.RLock() + curTotalTxns := b.stateSnapshot.TotalTxns + b.stateLock.RUnlock() + numTxns := uint64(len(block.MsgBlock().Transactions)) + blockSize := uint64(block.MsgBlock().SerializeSize()) + blockWeight := uint64(GetBlockWeight(block)) + state := newBestState(node, blockSize, blockWeight, numTxns, + curTotalTxns+numTxns, node.CalcPastMedianTime()) + + // Atomically insert info into the database. + err = b.db.Update(func(dbTx database.Tx) error { + // Update best block state. + err := dbPutBestState(dbTx, state, node.workSum) + if err != nil { + return err + } + + // Add the block hash and height to the block index which tracks + // the main chain. + err = dbPutBlockIndex(dbTx, block.Hash(), node.height) + if err != nil { + return err + } + + // Update the utxo set using the state of the utxo view. This + // entails removing all of the utxos spent and adding the new + // ones created by the block. + err = dbPutUtxoView(dbTx, view) + if err != nil { + return err + } + + // Update the transaction spend journal by adding a record for + // the block that contains all txos spent by it. + err = dbPutSpendJournalEntry(dbTx, block.Hash(), stxos) + if err != nil { + return err + } + + // Allow the index manager to call each of the currently active + // optional indexes with the block being connected so they can + // update themselves accordingly. + if b.indexManager != nil { + err := b.indexManager.ConnectBlock(dbTx, block, stxos) + if err != nil { + return err + } + } + + return nil + }) + if 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() + + // This node is now the end of the best chain. + b.bestChain.SetTip(node) + + // Update the state for the best block. Notice how this replaces the + // entire struct instead of updating the existing one. This effectively + // allows the old version to act as a snapshot which callers can use + // freely without needing to hold a lock for the duration. See the + // comments on the state variable for more details. + b.stateLock.Lock() + b.stateSnapshot = state + b.stateLock.Unlock() + + // 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.chainLock.Unlock() + b.sendNotification(NTBlockConnected, block) + b.chainLock.Lock() + + return nil +} + +// disconnectBlock handles disconnecting the passed node/block from the end of +// the main (best) chain. +// +// This function MUST be called with the chain state lock held (for writes). +func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view *UtxoViewpoint) error { + // Make sure the node being disconnected is the end of the best chain. + if !node.hash.IsEqual(&b.bestChain.Tip().hash) { + return AssertError("disconnectBlock must be called with the " + + "block at the end of the main chain") + } + + // Load the previous block since some details for it are needed below. + prevNode := node.parent + var prevBlock *btcutil.Block + err := b.db.View(func(dbTx database.Tx) error { + var err error + prevBlock, err = dbFetchBlockByNode(dbTx, prevNode) + return err + }) + if err != nil { + return err + } + + // Write any block status changes to DB before updating best state. + err = b.index.flushToDB() + if err != nil { + return err + } + + // Generate a new best state snapshot that will be used to update the + // database and later memory if all database updates are successful. + b.stateLock.RLock() + curTotalTxns := b.stateSnapshot.TotalTxns + b.stateLock.RUnlock() + numTxns := uint64(len(prevBlock.MsgBlock().Transactions)) + blockSize := uint64(prevBlock.MsgBlock().SerializeSize()) + blockWeight := uint64(GetBlockWeight(prevBlock)) + newTotalTxns := curTotalTxns - uint64(len(block.MsgBlock().Transactions)) + state := newBestState(prevNode, blockSize, blockWeight, numTxns, + newTotalTxns, prevNode.CalcPastMedianTime()) + + err = b.db.Update(func(dbTx database.Tx) error { + // Update best block state. + err := dbPutBestState(dbTx, state, node.workSum) + if err != nil { + return err + } + + // Remove the block hash and height from the block index which + // tracks the main chain. + err = dbRemoveBlockIndex(dbTx, block.Hash(), node.height) + if err != nil { + return err + } + + // Update the utxo set using the state of the utxo view. This + // entails restoring all of the utxos spent and removing the new + // ones created by the block. + err = dbPutUtxoView(dbTx, view) + if err != nil { + return err + } + + // Before we delete the spend journal entry for this back, + // we'll fetch it as is so the indexers can utilize if needed. + stxos, err := dbFetchSpendJournalEntry(dbTx, block) + if err != nil { + return err + } + + // Update the transaction spend journal by removing the record + // that contains all txos spent by the block. + err = dbRemoveSpendJournalEntry(dbTx, block.Hash()) + if err != nil { + return err + } + + // Allow the index manager to call each of the currently active + // optional indexes with the block being disconnected so they + // can update themselves accordingly. + if b.indexManager != nil { + err := b.indexManager.DisconnectBlock(dbTx, block, stxos) + if err != nil { + return err + } + } + + return nil + }) + if 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() + + // This node's parent is now the end of the best chain. + b.bestChain.SetTip(node.parent) + + // Update the state for the best block. Notice how this replaces the + // entire struct instead of updating the existing one. This effectively + // allows the old version to act as a snapshot which callers can use + // freely without needing to hold a lock for the duration. See the + // comments on the state variable for more details. + b.stateLock.Lock() + b.stateSnapshot = state + b.stateLock.Unlock() + + // 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.chainLock.Unlock() + b.sendNotification(NTBlockDisconnected, block) + b.chainLock.Lock() + + return nil +} + +// countSpentOutputs returns the number of utxos the passed block spends. +func countSpentOutputs(block *btcutil.Block) int { + // Exclude the coinbase transaction since it can't spend anything. + var numSpent int + for _, tx := range block.Transactions()[1:] { + numSpent += len(tx.MsgTx().TxIn) + } + return numSpent +} + +// reorganizeChain reorganizes the block chain by disconnecting the nodes in the +// detachNodes list and connecting the nodes in the attach list. It expects +// that the lists are already in the correct order and are in sync with the +// end of the current best chain. Specifically, nodes that are being +// disconnected must be in reverse order (think of popping them off the end of +// the chain) and nodes the are being attached must be in forwards order +// (think pushing them onto the end of the chain). +// +// This function may modify node statuses in the block index without flushing. +// +// This function MUST be called with the chain state lock held (for writes). +func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error { + // Nothing to do if no reorganize nodes were provided. + if detachNodes.Len() == 0 && attachNodes.Len() == 0 { + return nil + } + + // Ensure the provided nodes match the current best chain. + tip := b.bestChain.Tip() + if detachNodes.Len() != 0 { + firstDetachNode := detachNodes.Front().Value.(*blockNode) + if firstDetachNode.hash != tip.hash { + return AssertError(fmt.Sprintf("reorganize nodes to detach are "+ + "not for the current best chain -- first detach node %v, "+ + "current chain %v", &firstDetachNode.hash, &tip.hash)) + } + } + + // Ensure the provided nodes are for the same fork point. + if attachNodes.Len() != 0 && detachNodes.Len() != 0 { + firstAttachNode := attachNodes.Front().Value.(*blockNode) + lastDetachNode := detachNodes.Back().Value.(*blockNode) + if firstAttachNode.parent.hash != lastDetachNode.parent.hash { + return AssertError(fmt.Sprintf("reorganize nodes do not have the "+ + "same fork point -- first attach parent %v, last detach "+ + "parent %v", &firstAttachNode.parent.hash, + &lastDetachNode.parent.hash)) + } + } + + // Track the old and new best chains heads. + oldBest := tip + newBest := tip + + // All of the blocks to detach and related spend journal entries needed + // to unspend transaction outputs in the blocks being disconnected must + // be loaded from the database during the reorg check phase below and + // then they are needed again when doing the actual database updates. + // Rather than doing two loads, cache the loaded data into these slices. + detachBlocks := make([]*btcutil.Block, 0, detachNodes.Len()) + detachSpentTxOuts := make([][]SpentTxOut, 0, detachNodes.Len()) + attachBlocks := make([]*btcutil.Block, 0, attachNodes.Len()) + + // Disconnect all of the blocks back to the point of the fork. This + // entails loading the blocks and their associated spent txos from the + // database and using that information to unspend all of the spent txos + // and remove the utxos created by the blocks. + view := NewUtxoViewpoint() + view.SetBestHash(&oldBest.hash) + for e := detachNodes.Front(); e != nil; e = e.Next() { + n := e.Value.(*blockNode) + 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 + } + if n.hash != *block.Hash() { + return AssertError(fmt.Sprintf("detach block node hash %v (height "+ + "%v) does not match previous parent block hash %v", &n.hash, + n.height, block.Hash())) + } + + // Load all of the utxos referenced by the block that aren't + // already in the view. + err = view.fetchInputUtxos(b.db, block) + if err != nil { + return err + } + + // Load all of the spent txos for the block from the spend + // journal. + var stxos []SpentTxOut + err = b.db.View(func(dbTx database.Tx) error { + stxos, err = dbFetchSpendJournalEntry(dbTx, block) + return err + }) + if err != nil { + return err + } + + // Store the loaded block and spend journal entry for later. + detachBlocks = append(detachBlocks, block) + detachSpentTxOuts = append(detachSpentTxOuts, stxos) + + err = view.disconnectTransactions(b.db, block, stxos) + if err != nil { + return err + } + + newBest = n.parent + } + + // Set the fork point only if there are nodes to attach since otherwise + // blocks are only being disconnected and thus there is no fork point. + var forkNode *blockNode + if attachNodes.Len() > 0 { + forkNode = newBest + } + + // Perform several checks to verify each block that needs to be attached + // to the main chain can be connected without violating any rules and + // without actually connecting the block. + // + // NOTE: These checks could be done directly when connecting a block, + // however the downside to that approach is that if any of these checks + // fail after disconnecting some blocks or attaching others, all of the + // operations have to be rolled back to get the chain back into the + // state it was before the rule violation (or other failure). There are + // at least a couple of ways accomplish that rollback, but both involve + // tweaking the chain and/or database. This approach catches these + // issues before ever modifying the chain. + for e := attachNodes.Front(); e != nil; e = e.Next() { + n := e.Value.(*blockNode) + + 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 + } + + // Store the loaded block for later. + attachBlocks = append(attachBlocks, block) + + // Skip checks if node has already been fully validated. Although + // checkConnectBlock gets skipped, we still need to update the UTXO + // view. + if b.index.NodeStatus(n).KnownValid() { + err = view.fetchInputUtxos(b.db, block) + if err != nil { + return err + } + err = view.connectTransactions(block, nil) + if err != nil { + return err + } + + newBest = n + continue + } + + // Notice the spent txout details are not requested here and + // thus will not be generated. This is done because the state + // is not being immediately written to the database, so it is + // not needed. + // + // In the case the block is determined to be invalid due to a + // rule violation, mark it as invalid and mark all of its + // descendants as having an invalid ancestor. + err = b.checkConnectBlock(n, block, view, nil) + if err != nil { + if _, ok := err.(RuleError); ok { + b.index.SetStatusFlags(n, statusValidateFailed) + for de := e.Next(); de != nil; de = de.Next() { + dn := de.Value.(*blockNode) + b.index.SetStatusFlags(dn, statusInvalidAncestor) + } + } + return err + } + b.index.SetStatusFlags(n, statusValid) + + newBest = n + } + + // Reset the view for the actual connection code below. This is + // required because the view was previously modified when checking if + // the reorg would be successful and the connection code requires the + // view to be valid from the viewpoint of each block being connected or + // disconnected. + view = NewUtxoViewpoint() + view.SetBestHash(&b.bestChain.Tip().hash) + + // Disconnect blocks from the main chain. + for i, e := 0, detachNodes.Front(); e != nil; i, e = i+1, e.Next() { + n := e.Value.(*blockNode) + block := detachBlocks[i] + + // Load all of the utxos referenced by the block that aren't + // already in the view. + err := view.fetchInputUtxos(b.db, block) + if err != nil { + return err + } + + // Update the view to unspend all of the spent txos and remove + // the utxos created by the block. + err = view.disconnectTransactions(b.db, block, + detachSpentTxOuts[i]) + if err != nil { + return err + } + + // Update the database and chain state. + err = b.disconnectBlock(n, block, view) + if err != nil { + return err + } + } + + // Connect the new best chain blocks. + for i, e := 0, attachNodes.Front(); e != nil; i, e = i+1, e.Next() { + n := e.Value.(*blockNode) + block := attachBlocks[i] + + // Load all of the utxos referenced by the block that aren't + // already in the view. + err := view.fetchInputUtxos(b.db, block) + if err != nil { + return err + } + + // Update the view to mark all utxos referenced by the block + // as spent and add all transactions being created by this block + // to it. Also, provide an stxo slice so the spent txout + // details are generated. + stxos := make([]SpentTxOut, 0, countSpentOutputs(block)) + err = view.connectTransactions(block, &stxos) + if err != nil { + return err + } + + // Update the database and chain state. + err = b.connectBlock(n, block, view, stxos) + if err != nil { + return err + } + } + + // Log the point where the chain forked and old and new best chain + // heads. + if forkNode != nil { + log.Infof("REORGANIZE: Chain forks at %v (height %v)", forkNode.hash, + forkNode.height) + } + log.Infof("REORGANIZE: Old best chain head was %v (height %v)", + &oldBest.hash, oldBest.height) + log.Infof("REORGANIZE: New best chain head is %v (height %v)", + newBest.hash, newBest.height) + + return nil +} + +// connectBestChain handles connecting the passed block to the chain while +// respecting proper chain selection according to the chain with the most +// proof of work. In the typical case, the new block simply extends the main +// chain. However, it may also be extending (or creating) a side chain (fork) +// which may or may not end up becoming the main chain depending on which fork +// cumulatively has the most proof of work. It returns whether or not the block +// ended up on the main chain (either due to extending the main chain or causing +// 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. +// +// 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) { + fastAdd := flags&BFFastAdd == BFFastAdd + + flushIndexState := func() { + // Intentionally ignore errors writing updated node status to DB. If + // it fails to write, it's not the end of the world. If the block is + // valid, we flush in connectBlock and if the block is invalid, the + // worst that can happen is we revalidate the block after a restart. + if writeErr := b.index.flushToDB(); writeErr != nil { + log.Warnf("Error flushing block index changes to disk: %v", + writeErr) + } + } + + // We are extending the main (best) chain with a new block. This is the + // most common case. + parentHash := &block.MsgBlock().Header.PrevBlock + if parentHash.IsEqual(&b.bestChain.Tip().hash) { + // Skip checks if node has already been fully validated. + fastAdd = fastAdd || b.index.NodeStatus(node).KnownValid() + + // Perform several checks to verify the block can be connected + // to the main chain without violating any rules and without + // actually connecting the block. + view := NewUtxoViewpoint() + view.SetBestHash(parentHash) + stxos := make([]SpentTxOut, 0, countSpentOutputs(block)) + if !fastAdd { + err := b.checkConnectBlock(node, block, view, &stxos) + if err == nil { + b.index.SetStatusFlags(node, statusValid) + } else if _, ok := err.(RuleError); ok { + b.index.SetStatusFlags(node, statusValidateFailed) + } else { + return false, err + } + + flushIndexState() + + if err != nil { + return false, err + } + } + + // In the fast add case the code to check the block connection + // was skipped, so the utxo view needs to load the referenced + // utxos, spend them, and add the new utxos being created by + // this block. + if fastAdd { + err := view.fetchInputUtxos(b.db, block) + if err != nil { + return false, err + } + err = view.connectTransactions(block, &stxos) + if err != nil { + return false, err + } + } + + // Connect the block to the main chain. + err := b.connectBlock(node, block, view, stxos) + if err != nil { + // If we got hit with a rule error, then we'll mark + // 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.SetStatusFlags( + node, statusValidateFailed, + ) + } + + flushIndexState() + + return false, err + } + + // If this is fast add, or this block node isn't yet marked as + // valid, then we'll update its status and flush the state to + // disk again. + if fastAdd || !b.index.NodeStatus(node).KnownValid() { + b.index.SetStatusFlags(node, statusValid) + flushIndexState() + } + + return true, nil + } + if fastAdd { + log.Warnf("fastAdd set in the side chain case? %v\n", + block.Hash()) + } + + // We're extending (or creating) a side chain, but the cumulative + // work for this new side chain is not enough to make it the new chain. + if node.workSum.Cmp(b.bestChain.Tip().workSum) <= 0 { + // Log information about how the block is forking the chain. + fork := b.bestChain.FindFork(node) + if fork.hash.IsEqual(parentHash) { + log.Infof("FORK: Block %v forks the chain at height %d"+ + "/block %v, but does not cause a reorganize", + node.hash, fork.height, fork.hash) + } else { + log.Infof("EXTEND FORK: Block %v extends a side chain "+ + "which forks the chain at height %d/block %v", + node.hash, fork.height, fork.hash) + } + + return false, nil + } + + // We're extending (or creating) a side chain and the cumulative work + // for this new side chain is more than the old best chain, so this side + // chain needs to become the main chain. In order to accomplish that, + // find the common ancestor of both sides of the fork, disconnect the + // blocks that form the (now) old fork from the main chain, and attach + // the blocks that form the new chain to the main chain starting at the + // common ancenstor (the point where the chain forked). + detachNodes, attachNodes := b.getReorganizeNodes(node) + + // Reorganize the chain. + log.Infof("REORGANIZE: Block %v is causing a reorganize.", node.hash) + err := b.reorganizeChain(detachNodes, attachNodes) + + // Either getReorganizeNodes or reorganizeChain could have made unsaved + // changes to the block index, so flush regardless of whether there was an + // error. The index would only be dirty if the block failed to connect, so + // we can ignore any errors writing. + if writeErr := b.index.flushToDB(); writeErr != nil { + log.Warnf("Error flushing block index changes to disk: %v", writeErr) + } + + return err == nil, err +} + +// 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 +// +// This function MUST be called with the chain state lock held (for reads). +func (b *BlockChain) isCurrent() bool { + // Not current if the latest main (best) chain height is before the + // latest known good checkpoint (when checkpoints are enabled). + checkpoint := b.LatestCheckpoint() + if checkpoint != nil && b.bestChain.Tip().height < checkpoint.Height { + return false + } + + // Not current if the latest best block has a timestamp before 24 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 +} + +// 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 +// +// This function is safe for concurrent access. +func (b *BlockChain) IsCurrent() bool { + b.chainLock.RLock() + defer b.chainLock.RUnlock() + + return b.isCurrent() +} + +// BestSnapshot returns information about the current best chain block and +// related state as of the current point in time. The returned instance must be +// treated as immutable since it is shared by all callers. +// +// This function is safe for concurrent access. +func (b *BlockChain) BestSnapshot() *BestState { + b.stateLock.RLock() + snapshot := b.stateSnapshot + b.stateLock.RUnlock() + return snapshot +} + +// HeaderByHash returns the block header identified by the given hash or an +// error if it doesn't exist. Note that this will return headers from both the +// main and side chains. +func (b *BlockChain) HeaderByHash(hash *chainhash.Hash) (wire.BlockHeader, error) { + node := b.index.LookupNode(hash) + if node == nil { + err := fmt.Errorf("block %s is not known", hash) + return wire.BlockHeader{}, err + } + + return node.Header(), nil +} + +// MainChainHasBlock returns whether or not the block with the given hash is in +// the main chain. +// +// This function is safe for concurrent access. +func (b *BlockChain) MainChainHasBlock(hash *chainhash.Hash) bool { + node := b.index.LookupNode(hash) + return node != nil && b.bestChain.Contains(node) +} + +// BlockLocatorFromHash returns a block locator for the passed block hash. +// See BlockLocator for details on the algorithm used to create a block locator. +// +// In addition to the general algorithm referenced above, this function will +// return the block locator for the latest known tip of the main (best) chain if +// the passed hash is not currently known. +// +// This function is safe for concurrent access. +func (b *BlockChain) BlockLocatorFromHash(hash *chainhash.Hash) BlockLocator { + b.chainLock.RLock() + node := b.index.LookupNode(hash) + locator := b.bestChain.blockLocator(node) + b.chainLock.RUnlock() + return locator +} + +// LatestBlockLocator returns a block locator for the latest known tip of the +// main (best) chain. +// +// This function is safe for concurrent access. +func (b *BlockChain) LatestBlockLocator() (BlockLocator, error) { + b.chainLock.RLock() + locator := b.bestChain.BlockLocator(nil) + b.chainLock.RUnlock() + return locator, nil +} + +// BlockHeightByHash returns the height of the block with the given hash in the +// main chain. +// +// This function is safe for concurrent access. +func (b *BlockChain) BlockHeightByHash(hash *chainhash.Hash) (int32, error) { + node := b.index.LookupNode(hash) + if node == nil || !b.bestChain.Contains(node) { + str := fmt.Sprintf("block %s is not in the main chain", hash) + return 0, errNotInMainChain(str) + } + + return node.height, nil +} + +// BlockHashByHeight returns the hash of the block at the given height in the +// main chain. +// +// This function is safe for concurrent access. +func (b *BlockChain) BlockHashByHeight(blockHeight int32) (*chainhash.Hash, error) { + node := b.bestChain.NodeByHeight(blockHeight) + if node == nil { + str := fmt.Sprintf("no block at height %d exists", blockHeight) + return nil, errNotInMainChain(str) + + } + + return &node.hash, 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. +// +// This function is safe for concurrent access. +func (b *BlockChain) HeightRange(startHeight, endHeight int32) ([]chainhash.Hash, error) { + // Ensure requested heights are sane. + if startHeight < 0 { + return nil, fmt.Errorf("start height of fetch range must not "+ + "be less than zero - got %d", startHeight) + } + if endHeight < startHeight { + return nil, fmt.Errorf("end height of fetch range must not "+ + "be less than the start height - got start %d, end %d", + startHeight, endHeight) + } + + // There is nothing to do when the start and end heights are the same, + // so return now to avoid the chain view lock. + if startHeight == endHeight { + return nil, nil + } + + // Grab a lock on the chain view to prevent it from changing due to a + // reorg while building the hashes. + b.bestChain.mtx.Lock() + defer b.bestChain.mtx.Unlock() + + // When the requested start height is after the most recent best chain + // height, there is nothing to do. + latestHeight := b.bestChain.tip().height + if startHeight > latestHeight { + return nil, nil + } + + // Limit the ending height to the latest height of the chain. + if endHeight > latestHeight+1 { + endHeight = latestHeight + 1 + } + + // Fetch as many as are available within the specified range. + hashes := make([]chainhash.Hash, 0, endHeight-startHeight) + for i := startHeight; i < endHeight; i++ { + hashes = append(hashes, b.bestChain.nodeByHeight(i).hash) + } + return hashes, nil +} + +// HeightToHashRange returns a range of block hashes for the given start height +// and end hash, inclusive on both ends. The hashes are for all blocks that are +// ancestors of endHash with height greater than or equal to startHeight. The +// end hash must belong to a block that is known to be valid. +// +// This function is safe for concurrent access. +func (b *BlockChain) HeightToHashRange(startHeight int32, + endHash *chainhash.Hash, maxResults int) ([]chainhash.Hash, error) { + + endNode := b.index.LookupNode(endHash) + if endNode == nil { + return nil, fmt.Errorf("no known block header with hash %v", endHash) + } + if !b.index.NodeStatus(endNode).KnownValid() { + return nil, fmt.Errorf("block %v is not yet validated", endHash) + } + endHeight := endNode.height + + if startHeight < 0 { + return nil, fmt.Errorf("start height (%d) is below 0", startHeight) + } + if startHeight > endHeight { + return nil, fmt.Errorf("start height (%d) is past end height (%d)", + startHeight, endHeight) + } + + resultsLength := int(endHeight - startHeight + 1) + if resultsLength > maxResults { + return nil, fmt.Errorf("number of results (%d) would exceed max (%d)", + resultsLength, maxResults) + } + + // Walk backwards from endHeight to startHeight, collecting block hashes. + node := endNode + hashes := make([]chainhash.Hash, resultsLength) + for i := resultsLength - 1; i >= 0; i-- { + hashes[i] = node.hash + node = node.parent + } + return hashes, nil +} + +// IntervalBlockHashes returns hashes for all blocks that are ancestors of +// endHash where the block height is a positive multiple of interval. +// +// This function is safe for concurrent access. +func (b *BlockChain) IntervalBlockHashes(endHash *chainhash.Hash, interval int, +) ([]chainhash.Hash, error) { + + endNode := b.index.LookupNode(endHash) + if endNode == nil { + return nil, fmt.Errorf("no known block header with hash %v", endHash) + } + if !b.index.NodeStatus(endNode).KnownValid() { + return nil, fmt.Errorf("block %v is not yet validated", endHash) + } + endHeight := endNode.height + + resultsLength := int(endHeight) / interval + hashes := make([]chainhash.Hash, resultsLength) + + b.bestChain.mtx.Lock() + defer b.bestChain.mtx.Unlock() + + blockNode := endNode + for index := int(endHeight) / interval; index > 0; index-- { + // Use the bestChain chainView for faster lookups once lookup intersects + // the best chain. + blockHeight := int32(index * interval) + if b.bestChain.contains(blockNode) { + blockNode = b.bestChain.nodeByHeight(blockHeight) + } else { + blockNode = blockNode.Ancestor(blockHeight) + } + + hashes[index-1] = blockNode.hash + } + + return hashes, nil +} + +// locateInventory returns the node of the block after the first known block in +// the locator along with the number of subsequent nodes needed to either reach +// the provided stop hash or the provided max number of entries. +// +// 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 +// +// This is primarily a helper function for the locateBlocks and locateHeaders +// functions. +// +// This function MUST be called with the chain state lock held (for reads). +func (b *BlockChain) locateInventory(locator BlockLocator, hashStop *chainhash.Hash, maxEntries uint32) (*blockNode, uint32) { + // There are no block locators so a specific block is being requested + // as identified by the stop hash. + stopNode := b.index.LookupNode(hashStop) + if len(locator) == 0 { + if stopNode == nil { + // No blocks with the stop hash were found so there is + // nothing to do. + return nil, 0 + } + return stopNode, 1 + } + + // Find the most recent locator block hash in the main chain. In the + // case none of the hashes in the locator are in the main chain, fall + // back to the genesis block. + startNode := b.bestChain.Genesis() + for _, hash := range locator { + node := b.index.LookupNode(hash) + if node != nil && b.bestChain.Contains(node) { + startNode = node + break + } + } + + // Start at the block after the most recently known block. When there + // is no next block it means the most recently known block is the tip of + // the best chain, so there is nothing more to do. + startNode = b.bestChain.Next(startNode) + if startNode == nil { + return nil, 0 + } + + // Calculate how many entries are needed. + total := uint32((b.bestChain.Tip().height - startNode.height) + 1) + if stopNode != nil && b.bestChain.Contains(stopNode) && + stopNode.height >= startNode.height { + + total = uint32((stopNode.height - startNode.height) + 1) + } + if total > maxEntries { + total = maxEntries + } + + return startNode, total +} + +// locateBlocks returns the hashes of the blocks after the first known block in +// the locator until the provided stop hash is reached, or up to the provided +// max number of block hashes. +// +// See the comment on the exported function for more details on special cases. +// +// This function MUST be called with the chain state lock held (for reads). +func (b *BlockChain) locateBlocks(locator BlockLocator, hashStop *chainhash.Hash, maxHashes uint32) []chainhash.Hash { + // Find the node after the first known block in the locator and the + // total number of nodes after it needed while respecting the stop hash + // and max entries. + node, total := b.locateInventory(locator, hashStop, maxHashes) + if total == 0 { + return nil + } + + // Populate and return the found hashes. + hashes := make([]chainhash.Hash, 0, total) + for i := uint32(0); i < total; i++ { + hashes = append(hashes, node.hash) + node = b.bestChain.Next(node) + } + return hashes +} + +// LocateBlocks returns the hashes of the blocks after the first known block in +// the locator until the provided stop hash is reached, or up to the provided +// max number of block hashes. +// +// 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 +// +// This function is safe for concurrent access. +func (b *BlockChain) LocateBlocks(locator BlockLocator, hashStop *chainhash.Hash, maxHashes uint32) []chainhash.Hash { + b.chainLock.RLock() + hashes := b.locateBlocks(locator, hashStop, maxHashes) + b.chainLock.RUnlock() + return hashes +} + +// locateHeaders returns the headers of the blocks after the first known block +// in the locator until the provided stop hash is reached, or up to the provided +// max number of block headers. +// +// See the comment on the exported function for more details on special cases. +// +// This function MUST be called with the chain state lock held (for reads). +func (b *BlockChain) locateHeaders(locator BlockLocator, hashStop *chainhash.Hash, maxHeaders uint32) []wire.BlockHeader { + // Find the node after the first known block in the locator and the + // total number of nodes after it needed while respecting the stop hash + // and max entries. + node, total := b.locateInventory(locator, hashStop, maxHeaders) + if total == 0 { + return nil + } + + // Populate and return the found headers. + headers := make([]wire.BlockHeader, 0, total) + for i := uint32(0); i < total; i++ { + headers = append(headers, node.Header()) + node = b.bestChain.Next(node) + } + return headers +} + +// LocateHeaders returns the headers of the blocks after the first known block +// in the locator until the provided stop hash is reached, or up to a max of +// wire.MaxBlockHeadersPerMsg headers. +// +// 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 +// +// This function is safe for concurrent access. +func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Hash) []wire.BlockHeader { + b.chainLock.RLock() + headers := b.locateHeaders(locator, hashStop, wire.MaxBlockHeadersPerMsg) + b.chainLock.RUnlock() + return headers +} + +// 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. +type IndexManager interface { + // Init is invoked during chain initialize in order to allow the index + // manager to initialize itself and any indexes it is managing. The + // channel parameter specifies a channel the caller can close to signal + // that the process should be interrupted. It can be nil if that + // behavior is not desired. + Init(*BlockChain, <-chan struct{}) error + + // ConnectBlock is invoked when a new block has been connected to the + // main chain. The set of output spent within a block is also passed in + // so indexers can access the previous output scripts input spent if + // required. + ConnectBlock(database.Tx, *btcutil.Block, []SpentTxOut) error + + // DisconnectBlock is invoked when a block has been disconnected from + // the main chain. The set of outputs scripts that were spent within + // this block is also returned so indexers can clean up the prior index + // state for this block. + DisconnectBlock(database.Tx, *btcutil.Block, []SpentTxOut) error +} + +// Config is a descriptor which specifies the blockchain instance configuration. +type Config struct { + // DB defines the database which houses the blocks and will be used to + // store all metadata created by this package such as the utxo set. + // + // This field is required. + DB database.DB + + // Interrupt specifies a channel the caller can close to signal that + // long running operations, such as catching up indexes or performing + // database migrations, should be interrupted. + // + // This field can be nil if the caller does not desire the behavior. + Interrupt <-chan struct{} + + // ChainParams identifies which chain parameters the chain is associated + // with. + // + // This field is required. + ChainParams *chaincfg.Params + + // Checkpoints hold caller-defined checkpoints that should be added to + // the default checkpoints in ChainParams. Checkpoints must be sorted + // by height. + // + // This field can be nil if the caller does not wish to specify any + // checkpoints. + Checkpoints []chaincfg.Checkpoint + + // TimeSource defines the median time source to use for things such as + // block processing and determining whether or not the chain is current. + // + // The caller is expected to keep a reference to the time source as well + // and add time samples from other peers on the network so the local + // time is adjusted to be in agreement with other peers. + TimeSource MedianTimeSource + + // SigCache defines a signature cache to use when when validating + // signatures. This is typically most useful when individual + // transactions are already being validated prior to their inclusion in + // a block such as what is usually done via a transaction memory pool. + // + // This field can be nil if the caller is not interested in using a + // signature cache. + SigCache *txscript.SigCache + + // IndexManager defines an index manager to use when initializing the + // chain and connecting and disconnecting blocks. + // + // This field can be nil if the caller does not wish to make use of an + // index manager. + IndexManager IndexManager + + // HashCache defines a transaction hash mid-state cache to use when + // validating transactions. This cache has the potential to greatly + // speed up transaction validation as re-using the pre-calculated + // mid-state eliminates the O(N^2) validation complexity due to the + // SigHashAll flag. + // + // This field can be nil if the caller is not interested in using a + // signature cache. + HashCache *txscript.HashCache +} + +// New returns a BlockChain instance using the provided configuration details. +func New(config *Config) (*BlockChain, error) { + // Enforce required config fields. + if config.DB == nil { + return nil, AssertError("blockchain.New database is nil") + } + if config.ChainParams == nil { + return nil, AssertError("blockchain.New chain parameters nil") + } + if config.TimeSource == nil { + return nil, AssertError("blockchain.New timesource is nil") + } + + // Generate a checkpoint by height map from the provided checkpoints + // and assert the provided checkpoints are sorted by height as required. + var checkpointsByHeight map[int32]*chaincfg.Checkpoint + var prevCheckpointHeight int32 + if len(config.Checkpoints) > 0 { + checkpointsByHeight = make(map[int32]*chaincfg.Checkpoint) + for i := range config.Checkpoints { + checkpoint := &config.Checkpoints[i] + if checkpoint.Height <= prevCheckpointHeight { + return nil, AssertError("blockchain.New " + + "checkpoints are not sorted by height") + } + + checkpointsByHeight[checkpoint.Height] = checkpoint + prevCheckpointHeight = checkpoint.Height + } + } + + 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, + db: config.DB, + chainParams: params, + timeSource: config.TimeSource, + sigCache: config.SigCache, + indexManager: config.IndexManager, + minRetargetTimespan: targetTimespan / adjustmentFactor, + maxRetargetTimespan: targetTimespan * adjustmentFactor, + blocksPerRetarget: int32(targetTimespan / targetTimePerBlock), + index: newBlockIndex(config.DB, params), + hashCache: config.HashCache, + bestChain: newChainView(nil), + orphans: make(map[chainhash.Hash]*orphanBlock), + prevOrphans: make(map[chainhash.Hash][]*orphanBlock), + warningCaches: newThresholdCaches(vbNumBits), + deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments), + } + + // Initialize the chain state from the passed database. When the db + // does not yet contain any chain state, both it and the chain state + // will be initialized to contain only the genesis block. + if err := b.initChainState(); 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 + } + + // Initialize and catch up all of the currently active optional indexes + // as needed. + if config.IndexManager != nil { + err := config.IndexManager.Init(&b, config.Interrupt) + if err != nil { + return nil, err + } + } + + // Initialize rule change threshold state caches. + if err := b.initThresholdCaches(); err != nil { + 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, + bestNode.workSum) + + return &b, nil +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/chainio.go b/vendor/github.com/btcsuite/btcd/blockchain/chainio.go new file mode 100644 index 0000000..8d76d3c --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/chainio.go @@ -0,0 +1,1416 @@ +// Copyright (c) 2015-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 ( + "bytes" + "encoding/binary" + "fmt" + "math/big" + "sync" + "time" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/database" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" +) + +const ( + // blockHdrSize is the size of a block header. This is simply the + // constant from wire and is only provided here for convenience since + // wire.MaxBlockHeaderPayload is quite long. + blockHdrSize = wire.MaxBlockHeaderPayload + + // latestUtxoSetBucketVersion is the current version of the utxo set + // bucket that is used to track all unspent outputs. + latestUtxoSetBucketVersion = 2 + + // latestSpendJournalBucketVersion is the current version of the spend + // journal bucket that is used to track all spent transactions for use + // in reorgs. + latestSpendJournalBucketVersion = 1 +) + +var ( + // blockIndexBucketName is the name of the db bucket used to house to the + // block headers and contextual information. + blockIndexBucketName = []byte("blockheaderidx") + + // hashIndexBucketName is the name of the db bucket used to house to the + // block hash -> block height index. + hashIndexBucketName = []byte("hashidx") + + // heightIndexBucketName is the name of the db bucket used to house to + // the block height -> block hash index. + heightIndexBucketName = []byte("heightidx") + + // chainStateKeyName is the name of the db key used to store the best + // chain state. + chainStateKeyName = []byte("chainstate") + + // spendJournalVersionKeyName is the name of the db key used to store + // the version of the spend journal currently in the database. + spendJournalVersionKeyName = []byte("spendjournalversion") + + // spendJournalBucketName is the name of the db bucket used to house + // transactions outputs that are spent in each block. + spendJournalBucketName = []byte("spendjournal") + + // utxoSetVersionKeyName is the name of the db key used to store the + // version of the utxo set currently in the database. + utxoSetVersionKeyName = []byte("utxosetversion") + + // utxoSetBucketName is the name of the db bucket used to house the + // unspent transaction output set. + utxoSetBucketName = []byte("utxosetv2") + + // byteOrder is the preferred byte order used for serializing numeric + // fields for storage in the database. + byteOrder = binary.LittleEndian +) + +// errNotInMainChain signifies that a block hash or height that is not in the +// main chain was requested. +type errNotInMainChain string + +// Error implements the error interface. +func (e errNotInMainChain) Error() string { + return string(e) +} + +// isNotInMainChainErr returns whether or not the passed error is an +// errNotInMainChain error. +func isNotInMainChainErr(err error) bool { + _, ok := err.(errNotInMainChain) + return ok +} + +// errDeserialize signifies that a problem was encountered when deserializing +// data. +type errDeserialize string + +// Error implements the error interface. +func (e errDeserialize) Error() string { + return string(e) +} + +// isDeserializeErr returns whether or not the passed error is an errDeserialize +// error. +func isDeserializeErr(err error) bool { + _, ok := err.(errDeserialize) + return ok +} + +// isDbBucketNotFoundErr returns whether or not the passed error is a +// database.Error with an error code of database.ErrBucketNotFound. +func isDbBucketNotFoundErr(err error) bool { + dbErr, ok := err.(database.Error) + return ok && dbErr.ErrorCode == database.ErrBucketNotFound +} + +// dbFetchVersion fetches an individual version with the given key from the +// metadata bucket. It is primarily used to track versions on entities such as +// buckets. It returns zero if the provided key does not exist. +func dbFetchVersion(dbTx database.Tx, key []byte) uint32 { + serialized := dbTx.Metadata().Get(key) + if serialized == nil { + return 0 + } + + return byteOrder.Uint32(serialized[:]) +} + +// dbPutVersion uses an existing database transaction to update the provided +// key in the metadata bucket to the given version. It is primarily used to +// track versions on entities such as buckets. +func dbPutVersion(dbTx database.Tx, key []byte, version uint32) error { + var serialized [4]byte + byteOrder.PutUint32(serialized[:], version) + return dbTx.Metadata().Put(key, serialized[:]) +} + +// dbFetchOrCreateVersion uses an existing database transaction to attempt to +// fetch the provided key from the metadata bucket as a version and in the case +// it doesn't exist, it adds the entry with the provided default version and +// returns that. This is useful during upgrades to automatically handle loading +// and adding version keys as necessary. +func dbFetchOrCreateVersion(dbTx database.Tx, key []byte, defaultVersion uint32) (uint32, error) { + version := dbFetchVersion(dbTx, key) + if version == 0 { + version = defaultVersion + err := dbPutVersion(dbTx, key, version) + if err != nil { + return 0, err + } + } + + return version, nil +} + +// ----------------------------------------------------------------------------- +// The transaction spend journal consists of an entry for each block connected +// to the main chain which contains the transaction outputs the block spends +// serialized such that the order is the reverse of the order they were spent. +// +// This is required because reorganizing the chain necessarily entails +// disconnecting blocks to get back to the point of the fork which implies +// unspending all of the transaction outputs that each block previously spent. +// Since the utxo set, by definition, only contains unspent transaction outputs, +// the spent transaction outputs must be resurrected from somewhere. There is +// more than one way this could be done, however this is the most straight +// forward method that does not require having a transaction index and unpruned +// blockchain. +// +// NOTE: This format is NOT self describing. The additional details such as +// the number of entries (transaction inputs) are expected to come from the +// block itself and the utxo set (for legacy entries). The rationale in doing +// this is to save space. This is also the reason the spent outputs are +// serialized in the reverse order they are spent because later transactions are +// allowed to spend outputs from earlier ones in the same block. +// +// The reserved field below used to keep track of the version of the containing +// transaction when the height in the header code was non-zero, however the +// height is always non-zero now, but keeping the extra reserved field allows +// backwards compatibility. +// +// The serialized format is: +// +// [
],... +// +// Field Type Size +// header code VLQ variable +// reserved byte 1 +// compressed txout +// compressed amount VLQ variable +// compressed script []byte variable +// +// The serialized header code format is: +// bit 0 - containing transaction is a coinbase +// bits 1-x - height of the block that contains the spent txout +// +// Example 1: +// From block 170 in main blockchain. +// +// 1300320511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c +// <><><------------------------------------------------------------------> +// | | | +// | reserved compressed txout +// header code +// +// - header code: 0x13 (coinbase, height 9) +// - reserved: 0x00 +// - compressed txout 0: +// - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC) +// - 0x05: special script type pay-to-pubkey +// - 0x11...5c: x-coordinate of the pubkey +// +// Example 2: +// Adapted from block 100025 in main blockchain. +// +// 8b99700091f20f006edbc6c4d31bae9f1ccc38538a114bf42de65e868b99700086c64700b2fb57eadf61e106a100a7445a8c3f67898841ec +// <----><><----------------------------------------------><----><><----------------------------------------------> +// | | | | | | +// | reserved compressed txout | reserved compressed txout +// header code header code +// +// - Last spent output: +// - header code: 0x8b9970 (not coinbase, height 100024) +// - reserved: 0x00 +// - compressed txout: +// - 0x91f20f: VLQ-encoded compressed amount for 34405000000 (344.05 BTC) +// - 0x00: special script type pay-to-pubkey-hash +// - 0x6e...86: pubkey hash +// - Second to last spent output: +// - header code: 0x8b9970 (not coinbase, height 100024) +// - reserved: 0x00 +// - compressed txout: +// - 0x86c647: VLQ-encoded compressed amount for 13761000000 (137.61 BTC) +// - 0x00: special script type pay-to-pubkey-hash +// - 0xb2...ec: pubkey hash +// ----------------------------------------------------------------------------- + +// SpentTxOut contains a spent transaction output and potentially additional +// contextual information such as whether or not it was contained in a coinbase +// transaction, the version of the transaction it was contained in, and which +// block height the containing transaction was included in. As described in +// the comments above, the additional contextual information will only be valid +// when this spent txout is spending the last unspent output of the containing +// transaction. +type SpentTxOut struct { + // Amount is the amount of the output. + Amount int64 + + // PkScipt is the the public key script for the output. + PkScript []byte + + // Height is the height of the the block containing the creating tx. + Height int32 + + // Denotes if the creating tx is a coinbase. + IsCoinBase bool +} + +// FetchSpendJournal attempts to retrieve the spend journal, or the set of +// outputs spent for the target block. This provides a view of all the outputs +// that will be consumed once the target block is connected to the end of the +// main chain. +// +// This function is safe for concurrent access. +func (b *BlockChain) FetchSpendJournal(targetBlock *btcutil.Block) ([]SpentTxOut, error) { + b.chainLock.RLock() + defer b.chainLock.RUnlock() + + var spendEntries []SpentTxOut + err := b.db.View(func(dbTx database.Tx) error { + var err error + + spendEntries, err = dbFetchSpendJournalEntry(dbTx, targetBlock) + return err + }) + if err != nil { + return nil, err + } + + return spendEntries, nil +} + +// spentTxOutHeaderCode returns the calculated header code to be used when +// serializing the provided stxo entry. +func spentTxOutHeaderCode(stxo *SpentTxOut) uint64 { + // As described in the serialization format comments, the header code + // encodes the height shifted over one bit and the coinbase flag in the + // lowest bit. + headerCode := uint64(stxo.Height) << 1 + if stxo.IsCoinBase { + headerCode |= 0x01 + } + + return headerCode +} + +// spentTxOutSerializeSize returns the number of bytes it would take to +// serialize the passed stxo according to the format described above. +func spentTxOutSerializeSize(stxo *SpentTxOut) int { + size := serializeSizeVLQ(spentTxOutHeaderCode(stxo)) + if stxo.Height > 0 { + // The legacy v1 spend journal format conditionally tracked the + // containing transaction version when the height was non-zero, + // so this is required for backwards compat. + size += serializeSizeVLQ(0) + } + return size + compressedTxOutSize(uint64(stxo.Amount), stxo.PkScript) +} + +// putSpentTxOut serializes the passed stxo according to the format described +// above directly into the passed target byte slice. The target byte slice must +// be at least large enough to handle the number of bytes returned by the +// SpentTxOutSerializeSize function or it will panic. +func putSpentTxOut(target []byte, stxo *SpentTxOut) int { + headerCode := spentTxOutHeaderCode(stxo) + offset := putVLQ(target, headerCode) + if stxo.Height > 0 { + // The legacy v1 spend journal format conditionally tracked the + // containing transaction version when the height was non-zero, + // so this is required for backwards compat. + offset += putVLQ(target[offset:], 0) + } + return offset + putCompressedTxOut(target[offset:], uint64(stxo.Amount), + stxo.PkScript) +} + +// decodeSpentTxOut decodes the passed serialized stxo entry, possibly followed +// by other data, into the passed stxo struct. It returns the number of bytes +// read. +func decodeSpentTxOut(serialized []byte, stxo *SpentTxOut) (int, error) { + // Ensure there are bytes to decode. + if len(serialized) == 0 { + return 0, errDeserialize("no serialized bytes") + } + + // Deserialize the header code. + code, offset := deserializeVLQ(serialized) + if offset >= len(serialized) { + return offset, errDeserialize("unexpected end of data after " + + "header code") + } + + // Decode the header code. + // + // Bit 0 indicates containing transaction is a coinbase. + // Bits 1-x encode height of containing transaction. + stxo.IsCoinBase = code&0x01 != 0 + stxo.Height = int32(code >> 1) + if stxo.Height > 0 { + // The legacy v1 spend journal format conditionally tracked the + // containing transaction version when the height was non-zero, + // so this is required for backwards compat. + _, bytesRead := deserializeVLQ(serialized[offset:]) + offset += bytesRead + if offset >= len(serialized) { + return offset, errDeserialize("unexpected end of data " + + "after reserved") + } + } + + // Decode the compressed txout. + amount, pkScript, bytesRead, err := decodeCompressedTxOut( + serialized[offset:]) + offset += bytesRead + if err != nil { + return offset, errDeserialize(fmt.Sprintf("unable to decode "+ + "txout: %v", err)) + } + stxo.Amount = int64(amount) + stxo.PkScript = pkScript + return offset, nil +} + +// deserializeSpendJournalEntry decodes the passed serialized byte slice into a +// slice of spent txouts according to the format described in detail above. +// +// Since the serialization format is not self describing, as noted in the +// format comments, this function also requires the transactions that spend the +// txouts. +func deserializeSpendJournalEntry(serialized []byte, txns []*wire.MsgTx) ([]SpentTxOut, error) { + // Calculate the total number of stxos. + var numStxos int + for _, tx := range txns { + numStxos += len(tx.TxIn) + } + + // When a block has no spent txouts there is nothing to serialize. + if len(serialized) == 0 { + // Ensure the block actually has no stxos. This should never + // happen unless there is database corruption or an empty entry + // erroneously made its way into the database. + if numStxos != 0 { + return nil, AssertError(fmt.Sprintf("mismatched spend "+ + "journal serialization - no serialization for "+ + "expected %d stxos", numStxos)) + } + + return nil, nil + } + + // Loop backwards through all transactions so everything is read in + // reverse order to match the serialization order. + stxoIdx := numStxos - 1 + offset := 0 + stxos := make([]SpentTxOut, numStxos) + for txIdx := len(txns) - 1; txIdx > -1; txIdx-- { + tx := txns[txIdx] + + // Loop backwards through all of the transaction inputs and read + // the associated stxo. + for txInIdx := len(tx.TxIn) - 1; txInIdx > -1; txInIdx-- { + txIn := tx.TxIn[txInIdx] + stxo := &stxos[stxoIdx] + stxoIdx-- + + n, err := decodeSpentTxOut(serialized[offset:], stxo) + offset += n + if err != nil { + return nil, errDeserialize(fmt.Sprintf("unable "+ + "to decode stxo for %v: %v", + txIn.PreviousOutPoint, err)) + } + } + } + + return stxos, nil +} + +// serializeSpendJournalEntry serializes all of the passed spent txouts into a +// single byte slice according to the format described in detail above. +func serializeSpendJournalEntry(stxos []SpentTxOut) []byte { + if len(stxos) == 0 { + return nil + } + + // Calculate the size needed to serialize the entire journal entry. + var size int + for i := range stxos { + size += spentTxOutSerializeSize(&stxos[i]) + } + serialized := make([]byte, size) + + // Serialize each individual stxo directly into the slice in reverse + // order one after the other. + var offset int + for i := len(stxos) - 1; i > -1; i-- { + offset += putSpentTxOut(serialized[offset:], &stxos[i]) + } + + return serialized +} + +// dbFetchSpendJournalEntry fetches the spend journal entry for the passed block +// and deserializes it into a slice of spent txout entries. +// +// NOTE: Legacy entries will not have the coinbase flag or height set unless it +// was the final output spend in the containing transaction. It is up to the +// caller to handle this properly by looking the information up in the utxo set. +func dbFetchSpendJournalEntry(dbTx database.Tx, block *btcutil.Block) ([]SpentTxOut, error) { + // Exclude the coinbase transaction since it can't spend anything. + spendBucket := dbTx.Metadata().Bucket(spendJournalBucketName) + serialized := spendBucket.Get(block.Hash()[:]) + blockTxns := block.MsgBlock().Transactions[1:] + stxos, err := deserializeSpendJournalEntry(serialized, blockTxns) + if err != nil { + // Ensure any deserialization errors are returned as database + // corruption errors. + if isDeserializeErr(err) { + return nil, database.Error{ + ErrorCode: database.ErrCorruption, + Description: fmt.Sprintf("corrupt spend "+ + "information for %v: %v", block.Hash(), + err), + } + } + + return nil, err + } + + return stxos, nil +} + +// dbPutSpendJournalEntry uses an existing database transaction to update the +// spend journal entry for the given block hash using the provided slice of +// spent txouts. The spent txouts slice must contain an entry for every txout +// the transactions in the block spend in the order they are spent. +func dbPutSpendJournalEntry(dbTx database.Tx, blockHash *chainhash.Hash, stxos []SpentTxOut) error { + spendBucket := dbTx.Metadata().Bucket(spendJournalBucketName) + serialized := serializeSpendJournalEntry(stxos) + return spendBucket.Put(blockHash[:], serialized) +} + +// dbRemoveSpendJournalEntry uses an existing database transaction to remove the +// spend journal entry for the passed block hash. +func dbRemoveSpendJournalEntry(dbTx database.Tx, blockHash *chainhash.Hash) error { + spendBucket := dbTx.Metadata().Bucket(spendJournalBucketName) + return spendBucket.Delete(blockHash[:]) +} + +// ----------------------------------------------------------------------------- +// The unspent transaction output (utxo) set consists of an entry for each +// unspent output using a format that is optimized to reduce space using domain +// specific compression algorithms. This format is a slightly modified version +// of the format used in Bitcoin Core. +// +// Each entry is keyed by an outpoint as specified below. It is important to +// note that the key encoding uses a VLQ, which employs an MSB encoding so +// iteration of utxos when doing byte-wise comparisons will produce them in +// order. +// +// The serialized key format is: +// +// +// Field Type Size +// hash chainhash.Hash chainhash.HashSize +// output index VLQ variable +// +// The serialized value format is: +// +//
+// +// Field Type Size +// header code VLQ variable +// compressed txout +// compressed amount VLQ variable +// compressed script []byte variable +// +// The serialized header code format is: +// bit 0 - containing transaction is a coinbase +// bits 1-x - height of the block that contains the unspent txout +// +// Example 1: +// From tx in main blockchain: +// Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098:0 +// +// 03320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52 +// <><------------------------------------------------------------------> +// | | +// header code compressed txout +// +// - header code: 0x03 (coinbase, height 1) +// - compressed txout: +// - 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:2 +// +// 8cf316800900b8025be1b3efc63b0ad48e7f9f10e87544528d58 +// <----><------------------------------------------> +// | | +// header code compressed txout +// +// - header code: 0x8cf316 (not coinbase, height 113931) +// - compressed txout: +// - 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:22 +// +// a8a2588ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6 +// <----><--------------------------------------------------> +// | | +// header code compressed txout +// +// - header code: 0xa8a258 (not coinbase, height 338156) +// - compressed txout: +// - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC) +// - 0x01: special script type pay-to-script-hash +// - 0x1d...e6: script hash +// ----------------------------------------------------------------------------- + +// maxUint32VLQSerializeSize is the maximum number of bytes a max uint32 takes +// to serialize as a VLQ. +var maxUint32VLQSerializeSize = serializeSizeVLQ(1<<32 - 1) + +// outpointKeyPool defines a concurrent safe free list of byte slices used to +// provide temporary buffers for outpoint database keys. +var outpointKeyPool = sync.Pool{ + New: func() interface{} { + b := make([]byte, chainhash.HashSize+maxUint32VLQSerializeSize) + return &b // Pointer to slice to avoid boxing alloc. + }, +} + +// outpointKey returns a key suitable for use as a database key in the utxo set +// while making use of a free list. A new buffer is allocated if there are not +// already any available on the free list. The returned byte slice should be +// returned to the free list by using the recycleOutpointKey function when the +// caller is done with it _unless_ the slice will need to live for longer than +// the caller can calculate such as when used to write to the database. +func outpointKey(outpoint wire.OutPoint) *[]byte { + // A VLQ employs an MSB encoding, so they are useful not only to reduce + // the amount of storage space, but also so iteration of utxos when + // doing byte-wise comparisons will produce them in order. + key := outpointKeyPool.Get().(*[]byte) + idx := uint64(outpoint.Index) + *key = (*key)[:chainhash.HashSize+serializeSizeVLQ(idx)] + copy(*key, outpoint.Hash[:]) + putVLQ((*key)[chainhash.HashSize:], idx) + return key +} + +// recycleOutpointKey puts the provided byte slice, which should have been +// obtained via the outpointKey function, back on the free list. +func recycleOutpointKey(key *[]byte) { + outpointKeyPool.Put(key) +} + +// utxoEntryHeaderCode returns the calculated header code to be used when +// serializing the provided utxo entry. +func utxoEntryHeaderCode(entry *UtxoEntry) (uint64, error) { + if entry.IsSpent() { + return 0, AssertError("attempt to serialize spent utxo header") + } + + // As described in the serialization format comments, the header code + // encodes the height shifted over one bit and the coinbase flag in the + // lowest bit. + headerCode := uint64(entry.BlockHeight()) << 1 + if entry.IsCoinBase() { + headerCode |= 0x01 + } + + return headerCode, nil +} + +// serializeUtxoEntry returns the entry serialized to a format that is suitable +// for long-term storage. The format is described in detail above. +func serializeUtxoEntry(entry *UtxoEntry) ([]byte, error) { + // Spent outputs have no serialization. + if entry.IsSpent() { + return nil, nil + } + + // Encode the header code. + headerCode, err := utxoEntryHeaderCode(entry) + if err != nil { + return nil, err + } + + // Calculate the size needed to serialize the entry. + size := serializeSizeVLQ(headerCode) + + compressedTxOutSize(uint64(entry.Amount()), entry.PkScript()) + + // Serialize the header code followed by the compressed unspent + // transaction output. + serialized := make([]byte, size) + offset := putVLQ(serialized, headerCode) + offset += putCompressedTxOut(serialized[offset:], uint64(entry.Amount()), + entry.PkScript()) + + return serialized, nil +} + +// deserializeUtxoEntry decodes a utxo entry from the passed serialized byte +// slice into a new UtxoEntry using a format that is suitable for long-term +// storage. The format is described in detail above. +func deserializeUtxoEntry(serialized []byte) (*UtxoEntry, error) { + // Deserialize the header code. + code, offset := deserializeVLQ(serialized) + if offset >= len(serialized) { + return nil, errDeserialize("unexpected end of data after header") + } + + // Decode the header code. + // + // Bit 0 indicates whether the containing transaction is a coinbase. + // Bits 1-x encode height of containing transaction. + isCoinBase := code&0x01 != 0 + blockHeight := int32(code >> 1) + + // Decode the compressed unspent transaction output. + amount, pkScript, _, err := decodeCompressedTxOut(serialized[offset:]) + if err != nil { + return nil, errDeserialize(fmt.Sprintf("unable to decode "+ + "utxo: %v", err)) + } + + entry := &UtxoEntry{ + amount: int64(amount), + pkScript: pkScript, + blockHeight: blockHeight, + packedFlags: 0, + } + if isCoinBase { + entry.packedFlags |= tfCoinBase + } + + return entry, nil +} + +// dbFetchUtxoEntryByHash attempts to find and fetch a utxo for the given hash. +// It uses a cursor and seek to try and do this as efficiently as possible. +// +// When there are no entries for the provided hash, nil will be returned for the +// both the entry and the error. +func dbFetchUtxoEntryByHash(dbTx database.Tx, hash *chainhash.Hash) (*UtxoEntry, error) { + // Attempt to find an entry by seeking for the hash along with a zero + // index. Due to the fact the keys are serialized as , + // where the index uses an MSB encoding, if there are any entries for + // the hash at all, one will be found. + cursor := dbTx.Metadata().Bucket(utxoSetBucketName).Cursor() + key := outpointKey(wire.OutPoint{Hash: *hash, Index: 0}) + ok := cursor.Seek(*key) + recycleOutpointKey(key) + if !ok { + return nil, nil + } + + // An entry was found, but it could just be an entry with the next + // highest hash after the requested one, so make sure the hashes + // actually match. + cursorKey := cursor.Key() + if len(cursorKey) < chainhash.HashSize { + return nil, nil + } + if !bytes.Equal(hash[:], cursorKey[:chainhash.HashSize]) { + return nil, nil + } + + return deserializeUtxoEntry(cursor.Value()) +} + +// dbFetchUtxoEntry uses an existing database transaction to fetch the specified +// transaction output from the utxo set. +// +// When there is no entry for the provided output, nil will be returned for both +// the entry and the error. +func dbFetchUtxoEntry(dbTx database.Tx, outpoint wire.OutPoint) (*UtxoEntry, error) { + // Fetch the unspent transaction output information for the passed + // transaction output. Return now when there is no entry. + key := outpointKey(outpoint) + utxoBucket := dbTx.Metadata().Bucket(utxoSetBucketName) + serializedUtxo := utxoBucket.Get(*key) + recycleOutpointKey(key) + if serializedUtxo == nil { + return nil, nil + } + + // A non-nil zero-length entry means there is an entry in the database + // for a spent transaction output which should never be the case. + if len(serializedUtxo) == 0 { + return nil, AssertError(fmt.Sprintf("database contains entry "+ + "for spent tx output %v", outpoint)) + } + + // Deserialize the utxo entry and return it. + entry, err := deserializeUtxoEntry(serializedUtxo) + if err != nil { + // Ensure any deserialization errors are returned as database + // corruption errors. + if isDeserializeErr(err) { + return nil, database.Error{ + ErrorCode: database.ErrCorruption, + Description: fmt.Sprintf("corrupt utxo entry "+ + "for %v: %v", outpoint, err), + } + } + + return nil, err + } + + return entry, nil +} + +// dbPutUtxoView uses an existing database transaction to update the utxo set +// in the database based on the provided utxo view contents and state. In +// particular, only the entries that have been marked as modified are written +// to the database. +func dbPutUtxoView(dbTx database.Tx, view *UtxoViewpoint) error { + utxoBucket := dbTx.Metadata().Bucket(utxoSetBucketName) + for outpoint, entry := range view.entries { + // No need to update the database if the entry was not modified. + if entry == nil || !entry.isModified() { + continue + } + + // Remove the utxo entry if it is spent. + if entry.IsSpent() { + key := outpointKey(outpoint) + err := utxoBucket.Delete(*key) + recycleOutpointKey(key) + if err != nil { + return err + } + + continue + } + + // Serialize and store the utxo entry. + serialized, err := serializeUtxoEntry(entry) + if err != nil { + return err + } + key := outpointKey(outpoint) + err = utxoBucket.Put(*key, serialized) + // NOTE: The key is intentionally not recycled here since the + // database interface contract prohibits modifications. It will + // be garbage collected normally when the database is done with + // it. + if err != nil { + return err + } + } + + return nil +} + +// ----------------------------------------------------------------------------- +// The block index consists of two buckets with an entry for every block in the +// main chain. One bucket is for the hash to height mapping and the other is +// for the height to hash mapping. +// +// The serialized format for values in the hash to height bucket is: +// +// +// Field Type Size +// height uint32 4 bytes +// +// The serialized format for values in the height to hash bucket is: +// +// +// Field Type Size +// hash chainhash.Hash chainhash.HashSize +// ----------------------------------------------------------------------------- + +// dbPutBlockIndex uses an existing database transaction to update or add the +// block index entries for the hash to height and height to hash mappings for +// the provided values. +func dbPutBlockIndex(dbTx database.Tx, hash *chainhash.Hash, height int32) error { + // Serialize the height for use in the index entries. + var serializedHeight [4]byte + byteOrder.PutUint32(serializedHeight[:], uint32(height)) + + // Add the block hash to height mapping to the index. + meta := dbTx.Metadata() + hashIndex := meta.Bucket(hashIndexBucketName) + if err := hashIndex.Put(hash[:], serializedHeight[:]); err != nil { + return err + } + + // Add the block height to hash mapping to the index. + heightIndex := meta.Bucket(heightIndexBucketName) + return heightIndex.Put(serializedHeight[:], hash[:]) +} + +// dbRemoveBlockIndex uses an existing database transaction remove block index +// entries from the hash to height and height to hash mappings for the provided +// values. +func dbRemoveBlockIndex(dbTx database.Tx, hash *chainhash.Hash, height int32) error { + // Remove the block hash to height mapping. + meta := dbTx.Metadata() + hashIndex := meta.Bucket(hashIndexBucketName) + if err := hashIndex.Delete(hash[:]); err != nil { + return err + } + + // Remove the block height to hash mapping. + var serializedHeight [4]byte + byteOrder.PutUint32(serializedHeight[:], uint32(height)) + heightIndex := meta.Bucket(heightIndexBucketName) + return heightIndex.Delete(serializedHeight[:]) +} + +// dbFetchHeightByHash uses an existing database transaction to retrieve the +// height for the provided hash from the index. +func dbFetchHeightByHash(dbTx database.Tx, hash *chainhash.Hash) (int32, error) { + meta := dbTx.Metadata() + hashIndex := meta.Bucket(hashIndexBucketName) + serializedHeight := hashIndex.Get(hash[:]) + if serializedHeight == nil { + str := fmt.Sprintf("block %s is not in the main chain", hash) + return 0, errNotInMainChain(str) + } + + return int32(byteOrder.Uint32(serializedHeight)), nil +} + +// dbFetchHashByHeight uses an existing database transaction to retrieve the +// hash for the provided height from the index. +func dbFetchHashByHeight(dbTx database.Tx, height int32) (*chainhash.Hash, error) { + var serializedHeight [4]byte + byteOrder.PutUint32(serializedHeight[:], uint32(height)) + + meta := dbTx.Metadata() + heightIndex := meta.Bucket(heightIndexBucketName) + hashBytes := heightIndex.Get(serializedHeight[:]) + if hashBytes == nil { + str := fmt.Sprintf("no block at height %d exists", height) + return nil, errNotInMainChain(str) + } + + var hash chainhash.Hash + copy(hash[:], hashBytes) + return &hash, nil +} + +// ----------------------------------------------------------------------------- +// The best chain state consists of the best block hash and height, the total +// number of transactions up to and including those in the best block, and the +// accumulated work sum up to and including the best block. +// +// The serialized format is: +// +// +// +// Field Type Size +// block hash chainhash.Hash chainhash.HashSize +// block height uint32 4 bytes +// total txns uint64 8 bytes +// work sum length uint32 4 bytes +// work sum big.Int work sum length +// ----------------------------------------------------------------------------- + +// bestChainState represents the data to be stored the database for the current +// best chain state. +type bestChainState struct { + hash chainhash.Hash + height uint32 + totalTxns uint64 + workSum *big.Int +} + +// serializeBestChainState returns the serialization of the passed block best +// chain state. This is data to be stored in the chain state bucket. +func serializeBestChainState(state bestChainState) []byte { + // Calculate the full size needed to serialize the chain state. + workSumBytes := state.workSum.Bytes() + workSumBytesLen := uint32(len(workSumBytes)) + serializedLen := chainhash.HashSize + 4 + 8 + 4 + workSumBytesLen + + // Serialize the chain state. + serializedData := make([]byte, serializedLen) + copy(serializedData[0:chainhash.HashSize], state.hash[:]) + offset := uint32(chainhash.HashSize) + byteOrder.PutUint32(serializedData[offset:], state.height) + offset += 4 + byteOrder.PutUint64(serializedData[offset:], state.totalTxns) + offset += 8 + byteOrder.PutUint32(serializedData[offset:], workSumBytesLen) + offset += 4 + copy(serializedData[offset:], workSumBytes) + return serializedData[:] +} + +// deserializeBestChainState deserializes the passed serialized best chain +// state. This is data stored in the chain state bucket and is updated after +// every block is connected or disconnected form the main chain. +// block. +func deserializeBestChainState(serializedData []byte) (bestChainState, error) { + // Ensure the serialized data has enough bytes to properly deserialize + // the hash, height, total transactions, and work sum length. + if len(serializedData) < chainhash.HashSize+16 { + return bestChainState{}, database.Error{ + ErrorCode: database.ErrCorruption, + Description: "corrupt best chain state", + } + } + + state := bestChainState{} + copy(state.hash[:], serializedData[0:chainhash.HashSize]) + offset := uint32(chainhash.HashSize) + state.height = byteOrder.Uint32(serializedData[offset : offset+4]) + offset += 4 + state.totalTxns = byteOrder.Uint64(serializedData[offset : offset+8]) + offset += 8 + workSumBytesLen := byteOrder.Uint32(serializedData[offset : offset+4]) + offset += 4 + + // Ensure the serialized data has enough bytes to deserialize the work + // sum. + if uint32(len(serializedData[offset:])) < workSumBytesLen { + return bestChainState{}, database.Error{ + ErrorCode: database.ErrCorruption, + Description: "corrupt best chain state", + } + } + workSumBytes := serializedData[offset : offset+workSumBytesLen] + state.workSum = new(big.Int).SetBytes(workSumBytes) + + return state, nil +} + +// dbPutBestState uses an existing database transaction to update the best chain +// state with the given parameters. +func dbPutBestState(dbTx database.Tx, snapshot *BestState, workSum *big.Int) error { + // Serialize the current best chain state. + serializedData := serializeBestChainState(bestChainState{ + hash: snapshot.Hash, + height: uint32(snapshot.Height), + totalTxns: snapshot.TotalTxns, + workSum: workSum, + }) + + // Store the current best chain state into the database. + return dbTx.Metadata().Put(chainStateKeyName, serializedData) +} + +// createChainState initializes both the database and the chain state to the +// genesis block. This includes creating the necessary buckets and inserting +// the genesis block, so it must only be called on an uninitialized database. +func (b *BlockChain) createChainState() error { + // Create a new node from the genesis block and set it as the best node. + genesisBlock := btcutil.NewBlock(b.chainParams.GenesisBlock) + genesisBlock.SetHeight(0) + header := &genesisBlock.MsgBlock().Header + node := newBlockNode(header, nil) + node.status = statusDataStored | statusValid + b.bestChain.SetTip(node) + + // Add the new node to the index which is used for faster lookups. + b.index.addNode(node) + + // Initialize the state related to the best block. Since it is the + // genesis block, use its timestamp for the median time. + numTxns := uint64(len(genesisBlock.MsgBlock().Transactions)) + blockSize := uint64(genesisBlock.MsgBlock().SerializeSize()) + blockWeight := uint64(GetBlockWeight(genesisBlock)) + b.stateSnapshot = newBestState(node, blockSize, blockWeight, numTxns, + numTxns, time.Unix(node.timestamp, 0)) + + // Create the initial the database chain state including creating the + // necessary index buckets and inserting the genesis block. + err := b.db.Update(func(dbTx database.Tx) error { + meta := dbTx.Metadata() + + // Create the bucket that houses the block index data. + _, err := meta.CreateBucket(blockIndexBucketName) + if err != nil { + return err + } + + // Create the bucket that houses the chain block hash to height + // index. + _, err = meta.CreateBucket(hashIndexBucketName) + if err != nil { + return err + } + + // Create the bucket that houses the chain block height to hash + // index. + _, err = meta.CreateBucket(heightIndexBucketName) + if err != nil { + return err + } + + // Create the bucket that houses the spend journal data and + // store its version. + _, err = meta.CreateBucket(spendJournalBucketName) + if err != nil { + return err + } + err = dbPutVersion(dbTx, utxoSetVersionKeyName, + latestUtxoSetBucketVersion) + if err != nil { + return err + } + + // Create the bucket that houses the utxo set and store its + // version. Note that the genesis block coinbase transaction is + // intentionally not inserted here since it is not spendable by + // consensus rules. + _, err = meta.CreateBucket(utxoSetBucketName) + if err != nil { + return err + } + err = dbPutVersion(dbTx, spendJournalVersionKeyName, + latestSpendJournalBucketVersion) + if err != nil { + return err + } + + // Save the genesis block to the block index database. + err = dbStoreBlockNode(dbTx, node) + if err != nil { + return err + } + + // Add the genesis block hash to height and height to hash + // mappings to the index. + err = dbPutBlockIndex(dbTx, &node.hash, node.height) + if err != nil { + return err + } + + // Store the current best chain state into the database. + err = dbPutBestState(dbTx, b.stateSnapshot, node.workSum) + if err != nil { + return err + } + + // Store the genesis block into the database. + return dbStoreBlock(dbTx, genesisBlock) + }) + return err +} + +// initChainState attempts to load and initialize the chain state from the +// database. When the db does not yet contain any chain state, both it and the +// chain state are initialized to the genesis block. +func (b *BlockChain) initChainState() error { + // Determine the state of the chain database. We may need to initialize + // everything from scratch or upgrade certain buckets. + var initialized, hasBlockIndex bool + err := b.db.View(func(dbTx database.Tx) error { + initialized = dbTx.Metadata().Get(chainStateKeyName) != nil + hasBlockIndex = dbTx.Metadata().Bucket(blockIndexBucketName) != nil + return nil + }) + if err != nil { + return err + } + + if !initialized { + // At this point the database has not already been initialized, so + // initialize both it and the chain state to the genesis block. + return b.createChainState() + } + + if !hasBlockIndex { + err := migrateBlockIndex(b.db) + if err != nil { + return nil + } + } + + // Attempt to load the chain state from the database. + err = b.db.View(func(dbTx database.Tx) error { + // Fetch the stored chain state from the database metadata. + // When it doesn't exist, it means the database hasn't been + // initialized for use with chain yet, so break out now to allow + // that to happen under a writable database transaction. + serializedData := dbTx.Metadata().Get(chainStateKeyName) + log.Tracef("Serialized chain state: %x", serializedData) + state, err := deserializeBestChainState(serializedData) + if err != nil { + return err + } + + // Load all of the headers from the data for the known best + // chain and construct the block index accordingly. Since the + // number of nodes are already known, perform a single alloc + // for them versus a whole bunch of little ones to reduce + // pressure on the GC. + log.Infof("Loading block index...") + + blockIndexBucket := dbTx.Metadata().Bucket(blockIndexBucketName) + + // Determine how many blocks will be loaded into the index so we can + // allocate the right amount. + var blockCount int32 + cursor := blockIndexBucket.Cursor() + for ok := cursor.First(); ok; ok = cursor.Next() { + blockCount++ + } + blockNodes := make([]blockNode, blockCount) + + var i int32 + var lastNode *blockNode + cursor = blockIndexBucket.Cursor() + for ok := cursor.First(); ok; ok = cursor.Next() { + header, status, err := deserializeBlockRow(cursor.Value()) + if err != nil { + return err + } + + // Determine the parent block node. Since we iterate block headers + // in order of height, if the blocks are mostly linear there is a + // very good chance the previous header processed is the parent. + var parent *blockNode + if lastNode == nil { + blockHash := header.BlockHash() + if !blockHash.IsEqual(b.chainParams.GenesisHash) { + return AssertError(fmt.Sprintf("initChainState: Expected "+ + "first entry in block index to be genesis block, "+ + "found %s", blockHash)) + } + } else if header.PrevBlock == lastNode.hash { + // Since we iterate block headers in order of height, if the + // blocks are mostly linear there is a very good chance the + // previous header processed is the parent. + parent = lastNode + } else { + parent = b.index.LookupNode(&header.PrevBlock) + if parent == nil { + return AssertError(fmt.Sprintf("initChainState: Could "+ + "not find parent for block %s", header.BlockHash())) + } + } + + // Initialize the block node for the block, connect it, + // and add it to the block index. + node := &blockNodes[i] + initBlockNode(node, header, parent) + node.status = status + b.index.addNode(node) + + lastNode = node + i++ + } + + // Set the best chain view to the stored best state. + tip := b.index.LookupNode(&state.hash) + if tip == nil { + return AssertError(fmt.Sprintf("initChainState: cannot find "+ + "chain tip %s in block index", state.hash)) + } + b.bestChain.SetTip(tip) + + // Load the raw block bytes for the best block. + blockBytes, err := dbTx.FetchBlock(&state.hash) + if err != nil { + return err + } + var block wire.MsgBlock + err = block.Deserialize(bytes.NewReader(blockBytes)) + if err != nil { + return err + } + + // As a final consistency check, we'll run through all the + // nodes which are ancestors of the current chain tip, and mark + // them as valid if they aren't already marked as such. This + // is a safe assumption as all the block before the current tip + // are valid by definition. + for iterNode := tip; iterNode != nil; iterNode = iterNode.parent { + // If this isn't already marked as valid in the index, then + // we'll mark it as valid now to ensure consistency once + // we're up and running. + if !iterNode.status.KnownValid() { + log.Infof("Block %v (height=%v) ancestor of "+ + "chain tip not marked as valid, "+ + "upgrading to valid for consistency", + iterNode.hash, iterNode.height) + + b.index.SetStatusFlags(iterNode, statusValid) + } + } + + // Initialize the state related to the best block. + blockSize := uint64(len(blockBytes)) + blockWeight := uint64(GetBlockWeight(btcutil.NewBlock(&block))) + numTxns := uint64(len(block.Transactions)) + b.stateSnapshot = newBestState(tip, blockSize, blockWeight, + numTxns, state.totalTxns, tip.CalcPastMedianTime()) + + return nil + }) + if err != nil { + return err + } + + // As we might have updated the index after it was loaded, we'll + // attempt to flush the index to the DB. This will only result in a + // write if the elements are dirty, so it'll usually be a noop. + return b.index.flushToDB() +} + +// deserializeBlockRow parses a value in the block index bucket into a block +// header and block status bitfield. +func deserializeBlockRow(blockRow []byte) (*wire.BlockHeader, blockStatus, error) { + buffer := bytes.NewReader(blockRow) + + var header wire.BlockHeader + err := header.Deserialize(buffer) + if err != nil { + return nil, statusNone, err + } + + statusByte, err := buffer.ReadByte() + if err != nil { + return nil, statusNone, err + } + + return &header, blockStatus(statusByte), nil +} + +// dbFetchHeaderByHash uses an existing database transaction to retrieve the +// block header for the provided hash. +func dbFetchHeaderByHash(dbTx database.Tx, hash *chainhash.Hash) (*wire.BlockHeader, error) { + headerBytes, err := dbTx.FetchBlockHeader(hash) + if err != nil { + return nil, err + } + + var header wire.BlockHeader + err = header.Deserialize(bytes.NewReader(headerBytes)) + if err != nil { + return nil, err + } + + return &header, nil +} + +// dbFetchHeaderByHeight uses an existing database transaction to retrieve the +// block header for the provided height. +func dbFetchHeaderByHeight(dbTx database.Tx, height int32) (*wire.BlockHeader, error) { + hash, err := dbFetchHashByHeight(dbTx, height) + if err != nil { + return nil, err + } + + return dbFetchHeaderByHash(dbTx, hash) +} + +// dbFetchBlockByNode uses an existing database transaction to retrieve the +// raw block for the provided node, deserialize it, and return a btcutil.Block +// with the height set. +func dbFetchBlockByNode(dbTx database.Tx, node *blockNode) (*btcutil.Block, error) { + // Load the raw block bytes from the database. + blockBytes, err := dbTx.FetchBlock(&node.hash) + if err != nil { + return nil, err + } + + // Create the encapsulated block and set the height appropriately. + block, err := btcutil.NewBlockFromBytes(blockBytes) + if err != nil { + return nil, err + } + block.SetHeight(node.height) + + return block, nil +} + +// dbStoreBlockNode stores the block header and validation status to the block +// index bucket. This overwrites the current entry if there exists one. +func dbStoreBlockNode(dbTx database.Tx, node *blockNode) error { + // Serialize block data to be stored. + w := bytes.NewBuffer(make([]byte, 0, blockHdrSize+1)) + header := node.Header() + err := header.Serialize(w) + if err != nil { + return err + } + err = w.WriteByte(byte(node.status)) + if err != nil { + return err + } + value := w.Bytes() + + // Write block header data to block index bucket. + blockIndexBucket := dbTx.Metadata().Bucket(blockIndexBucketName) + key := blockIndexKey(&node.hash, uint32(node.height)) + return blockIndexBucket.Put(key, value) +} + +// dbStoreBlock stores the provided block in the database if it is not already +// there. The full block data is written to ffldb. +func dbStoreBlock(dbTx database.Tx, block *btcutil.Block) error { + hasBlock, err := dbTx.HasBlock(block.Hash()) + if err != nil { + return err + } + if hasBlock { + return nil + } + return dbTx.StoreBlock(block) +} + +// blockIndexKey generates the binary key for an entry in the block index +// bucket. The key is composed of the block height encoded as a big-endian +// 32-bit unsigned int followed by the 32 byte block hash. +func blockIndexKey(blockHash *chainhash.Hash, blockHeight uint32) []byte { + indexKey := make([]byte, chainhash.HashSize+4) + binary.BigEndian.PutUint32(indexKey[0:4], blockHeight) + copy(indexKey[4:chainhash.HashSize+4], blockHash[:]) + return indexKey +} + +// BlockByHeight returns the block at the given height in the main chain. +// +// This function is safe for concurrent access. +func (b *BlockChain) BlockByHeight(blockHeight int32) (*btcutil.Block, error) { + // Lookup the block height in the best chain. + node := b.bestChain.NodeByHeight(blockHeight) + if node == nil { + str := fmt.Sprintf("no block at height %d exists", blockHeight) + return nil, errNotInMainChain(str) + } + + // Load the block from the database and return it. + var block *btcutil.Block + err := b.db.View(func(dbTx database.Tx) error { + var err error + block, err = dbFetchBlockByNode(dbTx, node) + return err + }) + return block, err +} + +// BlockByHash returns the block from the main chain with the given hash with +// the appropriate chain height set. +// +// This function is safe for concurrent access. +func (b *BlockChain) BlockByHash(hash *chainhash.Hash) (*btcutil.Block, error) { + // Lookup the block hash in block index and ensure it is in the best + // chain. + node := b.index.LookupNode(hash) + if node == nil || !b.bestChain.Contains(node) { + str := fmt.Sprintf("block %s is not in the main chain", hash) + return nil, errNotInMainChain(str) + } + + // Load the block from the database and return it. + var block *btcutil.Block + err := b.db.View(func(dbTx database.Tx) error { + var err error + block, err = dbFetchBlockByNode(dbTx, node) + return err + }) + return block, err +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/chainview.go b/vendor/github.com/btcsuite/btcd/blockchain/chainview.go new file mode 100644 index 0000000..a4c3692 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/chainview.go @@ -0,0 +1,423 @@ +// 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 ( + "sync" +) + +// approxNodesPerWeek is an approximation of the number of new blocks there are +// in a week on average. +const approxNodesPerWeek = 6 * 24 * 7 + +// log2FloorMasks defines the masks to use when quickly calculating +// floor(log2(x)) in a constant log2(32) = 5 steps, where x is a uint32, using +// shifts. They are derived from (2^(2^x) - 1) * (2^(2^x)), for x in 4..0. +var log2FloorMasks = []uint32{0xffff0000, 0xff00, 0xf0, 0xc, 0x2} + +// fastLog2Floor calculates and returns floor(log2(x)) in a constant 5 steps. +func fastLog2Floor(n uint32) uint8 { + rv := uint8(0) + exponent := uint8(16) + for i := 0; i < 5; i++ { + if n&log2FloorMasks[i] != 0 { + rv += exponent + n >>= exponent + } + exponent >>= 1 + } + return rv +} + +// chainView provides a flat view of a specific branch of the block chain from +// its tip back to the genesis block and provides various convenience functions +// 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 +// +// The chain view for the branch ending in 6a consists of: +// genesis -> 1 -> 2 -> 3 -> 4a -> 5a -> 6a +type chainView struct { + mtx sync.Mutex + nodes []*blockNode +} + +// newChainView returns a new chain view for the given tip block node. Passing +// nil as the tip will result in a chain view that is not initialized. The tip +// can be updated at any time via the setTip function. +func newChainView(tip *blockNode) *chainView { + // The mutex is intentionally not held since this is a constructor. + var c chainView + c.setTip(tip) + return &c +} + +// genesis returns the genesis block for the chain view. This only differs from +// the exported version in that it is up to the caller to ensure the lock is +// held. +// +// This function MUST be called with the view mutex locked (for reads). +func (c *chainView) genesis() *blockNode { + if len(c.nodes) == 0 { + return nil + } + + return c.nodes[0] +} + +// Genesis returns the genesis block for the chain view. +// +// This function is safe for concurrent access. +func (c *chainView) Genesis() *blockNode { + c.mtx.Lock() + genesis := c.genesis() + c.mtx.Unlock() + return genesis +} + +// tip returns the current tip block node for the chain view. It will return +// nil if there is no tip. This only differs from the exported version in that +// it is up to the caller to ensure the lock is held. +// +// This function MUST be called with the view mutex locked (for reads). +func (c *chainView) tip() *blockNode { + if len(c.nodes) == 0 { + return nil + } + + return c.nodes[len(c.nodes)-1] +} + +// Tip returns the current tip block node for the chain view. It will return +// nil if there is no tip. +// +// This function is safe for concurrent access. +func (c *chainView) Tip() *blockNode { + c.mtx.Lock() + tip := c.tip() + c.mtx.Unlock() + return tip +} + +// setTip sets the chain view to use the provided block node as the current tip +// and ensures the view is consistent by populating it with the nodes obtained +// by walking backwards all the way to genesis block as necessary. Further +// calls will only perform the minimum work needed, so switching between chain +// tips is efficient. This only differs from the exported version in that it is +// up to the caller to ensure the lock is held. +// +// This function MUST be called with the view mutex locked (for writes). +func (c *chainView) setTip(node *blockNode) { + if node == nil { + // Keep the backing array around for potential future use. + c.nodes = c.nodes[:0] + return + } + + // Create or resize the slice that will hold the block nodes to the + // provided tip height. When creating the slice, it is created with + // some additional capacity for the underlying array as append would do + // in order to reduce overhead when extending the chain later. As long + // as the underlying array already has enough capacity, simply expand or + // contract the slice accordingly. The additional capacity is chosen + // such that the array should only have to be extended about once a + // week. + needed := node.height + 1 + if int32(cap(c.nodes)) < needed { + nodes := make([]*blockNode, needed, needed+approxNodesPerWeek) + copy(nodes, c.nodes) + c.nodes = nodes + } else { + prevLen := int32(len(c.nodes)) + c.nodes = c.nodes[0:needed] + for i := prevLen; i < needed; i++ { + c.nodes[i] = nil + } + } + + for node != nil && c.nodes[node.height] != node { + c.nodes[node.height] = node + node = node.parent + } +} + +// SetTip sets the chain view to use the provided block node as the current tip +// and ensures the view is consistent by populating it with the nodes obtained +// by walking backwards all the way to genesis block as necessary. Further +// calls will only perform the minimum work needed, so switching between chain +// tips is efficient. +// +// This function is safe for concurrent access. +func (c *chainView) SetTip(node *blockNode) { + c.mtx.Lock() + c.setTip(node) + c.mtx.Unlock() +} + +// height returns the height of the tip of the chain view. It will return -1 if +// there is no tip (which only happens if the chain view has not been +// initialized). This only differs from the exported version in that it is up +// to the caller to ensure the lock is held. +// +// This function MUST be called with the view mutex locked (for reads). +func (c *chainView) height() int32 { + return int32(len(c.nodes) - 1) +} + +// Height returns the height of the tip of the chain view. It will return -1 if +// there is no tip (which only happens if the chain view has not been +// initialized). +// +// This function is safe for concurrent access. +func (c *chainView) Height() int32 { + c.mtx.Lock() + height := c.height() + c.mtx.Unlock() + return height +} + +// nodeByHeight returns the block node at the specified height. Nil will be +// returned if the height does not exist. This only differs from the exported +// version in that it is up to the caller to ensure the lock is held. +// +// This function MUST be called with the view mutex locked (for reads). +func (c *chainView) nodeByHeight(height int32) *blockNode { + if height < 0 || height >= int32(len(c.nodes)) { + return nil + } + + return c.nodes[height] +} + +// NodeByHeight returns the block node at the specified height. Nil will be +// returned if the height does not exist. +// +// This function is safe for concurrent access. +func (c *chainView) NodeByHeight(height int32) *blockNode { + c.mtx.Lock() + node := c.nodeByHeight(height) + c.mtx.Unlock() + return node +} + +// Equals returns whether or not two chain views are the same. Uninitialized +// views (tip set to nil) are considered equal. +// +// This function is safe for concurrent access. +func (c *chainView) Equals(other *chainView) bool { + c.mtx.Lock() + other.mtx.Lock() + equals := len(c.nodes) == len(other.nodes) && c.tip() == other.tip() + other.mtx.Unlock() + c.mtx.Unlock() + return equals +} + +// contains returns whether or not the chain view contains the passed block +// node. This only differs from the exported version in that it is up to the +// caller to ensure the lock is held. +// +// This function MUST be called with the view mutex locked (for reads). +func (c *chainView) contains(node *blockNode) bool { + return c.nodeByHeight(node.height) == node +} + +// Contains returns whether or not the chain view contains the passed block +// node. +// +// This function is safe for concurrent access. +func (c *chainView) Contains(node *blockNode) bool { + c.mtx.Lock() + contains := c.contains(node) + c.mtx.Unlock() + return contains +} + +// next returns the successor to the provided node for the chain view. It will +// return nil if there is no successor or the provided node is not part of the +// view. This only differs from the exported version in that it is up to the +// caller to ensure the lock is held. +// +// See the comment on the exported function for more details. +// +// This function MUST be called with the view mutex locked (for reads). +func (c *chainView) next(node *blockNode) *blockNode { + if node == nil || !c.contains(node) { + return nil + } + + return c.nodeByHeight(node.height + 1) +} + +// Next returns the successor to the provided node for the chain view. It will +// return nil if there is no successfor or the provided node is not part of the +// 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 +// +// 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 +// +// 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 +// of the view. +// +// This function is safe for concurrent access. +func (c *chainView) Next(node *blockNode) *blockNode { + c.mtx.Lock() + next := c.next(node) + c.mtx.Unlock() + return next +} + +// findFork returns the final common block between the provided node and the +// the chain view. It will return nil if there is no common block. This only +// differs from the exported version in that it is up to the caller to ensure +// the lock is held. +// +// See the exported FindFork comments for more details. +// +// This function MUST be called with the view mutex locked (for reads). +func (c *chainView) findFork(node *blockNode) *blockNode { + // No fork point for node that doesn't exist. + if node == nil { + return nil + } + + // When the height of the passed node is higher than the height of the + // tip of the current chain view, walk backwards through the nodes of + // the other chain until the heights match (or there or no more nodes in + // which case there is no common node between the two). + // + // NOTE: This isn't strictly necessary as the following section will + // find the node as well, however, it is more efficient to avoid the + // contains check since it is already known that the common node can't + // possibly be past the end of the current chain view. It also allows + // this code to take advantage of any potential future optimizations to + // the Ancestor function such as using an O(log n) skip list. + chainHeight := c.height() + if node.height > chainHeight { + node = node.Ancestor(chainHeight) + } + + // Walk the other chain backwards as long as the current one does not + // contain the node or there are no more nodes in which case there is no + // common node between the two. + for node != nil && !c.contains(node) { + node = node.parent + } + + return node +} + +// FindFork returns the final common block between the provided node and the +// 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 +// +// 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. +// +// 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 +// the branch formed by the view. +// +// This function is safe for concurrent access. +func (c *chainView) FindFork(node *blockNode) *blockNode { + c.mtx.Lock() + fork := c.findFork(node) + c.mtx.Unlock() + return fork +} + +// blockLocator returns a block locator for the passed block node. The passed +// node can be nil in which case the block locator for the current tip +// associated with the view will be returned. This only differs from the +// exported version in that it is up to the caller to ensure the lock is held. +// +// See the exported BlockLocator function comments for more details. +// +// This function MUST be called with the view mutex locked (for reads). +func (c *chainView) blockLocator(node *blockNode) BlockLocator { + // Use the current tip if requested. + if node == nil { + node = c.tip() + } + if node == nil { + return nil + } + + // Calculate the max number of entries that will ultimately be in the + // block locator. See the description of the algorithm for how these + // numbers are derived. + var maxEntries uint8 + if node.height <= 12 { + maxEntries = uint8(node.height) + 1 + } else { + // Requested hash itself + previous 10 entries + genesis block. + // Then floor(log2(height-10)) entries for the skip portion. + adjustedHeight := uint32(node.height) - 10 + maxEntries = 12 + fastLog2Floor(adjustedHeight) + } + locator := make(BlockLocator, 0, maxEntries) + + step := int32(1) + for node != nil { + locator = append(locator, &node.hash) + + // Nothing more to add once the genesis block has been added. + if node.height == 0 { + break + } + + // Calculate height of previous node to include ensuring the + // final node is the genesis block. + height := node.height - step + if height < 0 { + height = 0 + } + + // When the node is in the current chain view, all of its + // ancestors must be too, so use a much faster O(1) lookup in + // that case. Otherwise, fall back to walking backwards through + // the nodes of the other chain to the correct ancestor. + if c.contains(node) { + node = c.nodes[height] + } else { + node = node.Ancestor(height) + } + + // Once 11 entries have been included, start doubling the + // distance between included hashes. + if len(locator) > 10 { + step *= 2 + } + } + + return locator +} + +// BlockLocator returns a block locator for the passed block node. The passed +// node can be nil in which case the block locator for the current tip +// associated with the view will be returned. +// +// See the BlockLocator type for details on the algorithm used to create a block +// locator. +// +// This function is safe for concurrent access. +func (c *chainView) BlockLocator(node *blockNode) BlockLocator { + c.mtx.Lock() + locator := c.blockLocator(node) + c.mtx.Unlock() + return locator +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/checkpoints.go b/vendor/github.com/btcsuite/btcd/blockchain/checkpoints.go new file mode 100644 index 0000000..af3b6d9 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/checkpoints.go @@ -0,0 +1,261 @@ +// Copyright (c) 2013-2016 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 ( + "fmt" + "time" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcutil" +) + +// CheckpointConfirmations is the number of blocks before the end of the current +// best block chain that a good checkpoint candidate must be. +const CheckpointConfirmations = 2016 + +// newHashFromStr converts the passed big-endian hex string into a +// chainhash.Hash. It only differs from the one available in chainhash in that +// it ignores the error since it will only (and must only) be called with +// hard-coded, and therefore known good, hashes. +func newHashFromStr(hexStr string) *chainhash.Hash { + hash, _ := chainhash.NewHashFromStr(hexStr) + return hash +} + +// Checkpoints returns a slice of checkpoints (regardless of whether they are +// already known). When there are no checkpoints for the chain, it will return +// nil. +// +// This function is safe for concurrent access. +func (b *BlockChain) Checkpoints() []chaincfg.Checkpoint { + return b.checkpoints +} + +// HasCheckpoints returns whether this BlockChain has checkpoints defined. +// +// This function is safe for concurrent access. +func (b *BlockChain) HasCheckpoints() bool { + return len(b.checkpoints) > 0 +} + +// LatestCheckpoint returns the most recent checkpoint (regardless of whether it +// is already known). When there are no defined checkpoints for the active chain +// instance, it will return nil. +// +// This function is safe for concurrent access. +func (b *BlockChain) LatestCheckpoint() *chaincfg.Checkpoint { + if !b.HasCheckpoints() { + return nil + } + return &b.checkpoints[len(b.checkpoints)-1] +} + +// verifyCheckpoint returns whether the passed block height and hash combination +// match the checkpoint data. It also returns true if there is no checkpoint +// data for the passed block height. +func (b *BlockChain) verifyCheckpoint(height int32, hash *chainhash.Hash) bool { + if !b.HasCheckpoints() { + return true + } + + // Nothing to check if there is no checkpoint data for the block height. + checkpoint, exists := b.checkpointsByHeight[height] + if !exists { + return true + } + + if !checkpoint.Hash.IsEqual(hash) { + return false + } + + log.Infof("Verified checkpoint at height %d/block %s", checkpoint.Height, + checkpoint.Hash) + return true +} + +// findPreviousCheckpoint finds the most recent checkpoint that is already +// available in the downloaded portion of the block chain and returns the +// associated block node. It returns nil if a checkpoint can't be found (this +// should really only happen for blocks before the first checkpoint). +// +// This function MUST be called with the chain lock held (for reads). +func (b *BlockChain) findPreviousCheckpoint() (*blockNode, error) { + if !b.HasCheckpoints() { + return nil, nil + } + + // Perform the initial search to find and cache the latest known + // checkpoint if the best chain is not known yet or we haven't already + // previously searched. + checkpoints := b.checkpoints + numCheckpoints := len(checkpoints) + if b.checkpointNode == nil && b.nextCheckpoint == nil { + // Loop backwards through the available checkpoints to find one + // that is already available. + for i := numCheckpoints - 1; i >= 0; i-- { + node := b.index.LookupNode(checkpoints[i].Hash) + if node == nil || !b.bestChain.Contains(node) { + continue + } + + // Checkpoint found. Cache it for future lookups and + // set the next expected checkpoint accordingly. + b.checkpointNode = node + if i < numCheckpoints-1 { + b.nextCheckpoint = &checkpoints[i+1] + } + return b.checkpointNode, nil + } + + // No known latest checkpoint. This will only happen on blocks + // before the first known checkpoint. So, set the next expected + // checkpoint to the first checkpoint and return the fact there + // is no latest known checkpoint block. + b.nextCheckpoint = &checkpoints[0] + return nil, nil + } + + // At this point we've already searched for the latest known checkpoint, + // so when there is no next checkpoint, the current checkpoint lockin + // will always be the latest known checkpoint. + if b.nextCheckpoint == nil { + return b.checkpointNode, nil + } + + // When there is a next checkpoint and the height of the current best + // chain does not exceed it, the current checkpoint lockin is still + // the latest known checkpoint. + if b.bestChain.Tip().height < b.nextCheckpoint.Height { + return b.checkpointNode, nil + } + + // We've reached or exceeded the next checkpoint height. Note that + // once a checkpoint lockin has been reached, forks are prevented from + // any blocks before the checkpoint, so we don't have to worry about the + // checkpoint going away out from under us due to a chain reorganize. + + // Cache the latest known checkpoint for future lookups. Note that if + // this lookup fails something is very wrong since the chain has already + // passed the checkpoint which was verified as accurate before inserting + // it. + checkpointNode := b.index.LookupNode(b.nextCheckpoint.Hash) + if checkpointNode == nil { + return nil, AssertError(fmt.Sprintf("findPreviousCheckpoint "+ + "failed lookup of known good block node %s", + b.nextCheckpoint.Hash)) + } + b.checkpointNode = checkpointNode + + // Set the next expected checkpoint. + checkpointIndex := -1 + for i := numCheckpoints - 1; i >= 0; i-- { + if checkpoints[i].Hash.IsEqual(b.nextCheckpoint.Hash) { + checkpointIndex = i + break + } + } + b.nextCheckpoint = nil + if checkpointIndex != -1 && checkpointIndex < numCheckpoints-1 { + b.nextCheckpoint = &checkpoints[checkpointIndex+1] + } + + return b.checkpointNode, nil +} + +// isNonstandardTransaction determines whether a transaction contains any +// scripts which are not one of the standard types. +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) + if scriptClass == txscript.NonStandardTy { + return true + } + } + return false +} + +// IsCheckpointCandidate returns whether or not the passed block is a good +// 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 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. +// +// This function is safe for concurrent access. +func (b *BlockChain) IsCheckpointCandidate(block *btcutil.Block) (bool, error) { + b.chainLock.RLock() + defer b.chainLock.RUnlock() + + // A checkpoint must be in the main chain. + node := b.index.LookupNode(block.Hash()) + if node == nil || !b.bestChain.Contains(node) { + return false, nil + } + + // Ensure the height of the passed block and the entry for the block in + // the main chain match. This should always be the case unless the + // caller provided an invalid block. + if node.height != block.Height() { + return false, fmt.Errorf("passed block height of %d does not "+ + "match the main chain height of %d", block.Height(), + node.height) + } + + // A checkpoint must be at least CheckpointConfirmations blocks + // before the end of the main chain. + mainChainHeight := b.bestChain.Tip().height + if node.height > (mainChainHeight - CheckpointConfirmations) { + return false, nil + } + + // A checkpoint must be have at least one block after it. + // + // This should always succeed since the check above already made sure it + // is CheckpointConfirmations back, but be safe in case the constant + // changes. + nextNode := b.bestChain.Next(node) + if nextNode == nil { + return false, nil + } + + // A checkpoint must be have at least one block before it. + if node.parent == nil { + return false, nil + } + + // A checkpoint must have timestamps for the block and the blocks on + // either side of it in order (due to the median time allowance this is + // not always the case). + prevTime := time.Unix(node.parent.timestamp, 0) + curTime := block.MsgBlock().Header.Timestamp + nextTime := time.Unix(nextNode.timestamp, 0) + if prevTime.After(curTime) || nextTime.Before(curTime) { + return false, nil + } + + // A checkpoint must have transactions that only contain standard + // scripts. + for _, tx := range block.Transactions() { + if isNonstandardTransaction(tx) { + return false, nil + } + } + + // All of the checks passed, so the block is a candidate. + return true, nil +} diff --git a/vendor/github.com/btcsuite/btcd/blockchain/compress.go b/vendor/github.com/btcsuite/btcd/blockchain/compress.go new file mode 100644 index 0000000..611b9f0 --- /dev/null +++ b/vendor/github.com/btcsuite/btcd/blockchain/compress.go @@ -0,0 +1,586 @@ +// Copyright (c) 2015-2016 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 ( + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/txscript" +) + +// ----------------------------------------------------------------------------- +// A variable length quantity (VLQ) is an encoding that uses an arbitrary number +// of binary octets to represent an arbitrarily large integer. The scheme +// employs a most significant byte (MSB) base-128 encoding where the high bit in +// each byte indicates whether or not the byte is the final one. In addition, +// to ensure there are no redundant encodings, an offset is subtracted every +// time a group of 7 bits is shifted out. Therefore each integer can be +// represented in exactly one way, and each representation stands for exactly +// one integer. +// +// Another nice property of this encoding is that it provides a compact +// representation of values that are typically used to indicate sizes. For +// example, the values 0 - 127 are represented with a single byte, 128 - 16511 +// with two bytes, and 16512 - 2113663 with three bytes. +// +// While the encoding allows arbitrarily large integers, it is artificially +// limited in this code to an unsigned 64-bit integer for efficiency purposes. +// +// Example encodings: +// 0 -> [0x00] +// 127 -> [0x7f] * Max 1-byte value +// 128 -> [0x80 0x00] +// 129 -> [0x80 0x01] +// 255 -> [0x80 0x7f] +// 256 -> [0x81 0x00] +// 16511 -> [0xff 0x7f] * Max 2-byte value +// 16512 -> [0x80 0x80 0x00] +// 32895 -> [0x80 0xff 0x7f] +// 2113663 -> [0xff 0xff 0x7f] * Max 3-byte value +// 270549119 -> [0xff 0xff 0xff 0x7f] * Max 4-byte value +// 2^64-1 -> [0x80 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0x7f] +// +// References: +// https://en.wikipedia.org/wiki/Variable-length_quantity +// http://www.codecodex.com/wiki/Variable-Length_Integers +// ----------------------------------------------------------------------------- + +// serializeSizeVLQ returns the number of bytes it would take to serialize the +// passed number as a variable-length quantity according to the format described +// above. +func serializeSizeVLQ(n uint64) int { + size := 1 + for ; n > 0x7f; n = (n >> 7) - 1 { + size++ + } + + return size +} + +// putVLQ serializes the provided number to a variable-length quantity according +// to the format described above and returns the number of bytes of the encoded +// value. The result is placed directly into the passed byte slice which must +// be at least large enough to handle the number of bytes returned by the +// serializeSizeVLQ function or it will panic. +func putVLQ(target []byte, n uint64) int { + offset := 0 + for ; ; offset++ { + // The high bit is set when another byte follows. + highBitMask := byte(0x80) + if offset == 0 { + highBitMask = 0x00 + } + + target[offset] = byte(n&0x7f) | highBitMask + if n <= 0x7f { + break + } + n = (n >> 7) - 1 + } + + // Reverse the bytes so it is MSB-encoded. + for i, j := 0, offset; i < j; i, j = i+1, j-1 { + target[i], target[j] = target[j], target[i] + } + + return offset + 1 +} + +// deserializeVLQ deserializes the provided variable-length quantity according +// to the format described above. It also returns the number of bytes +// deserialized. +func deserializeVLQ(serialized []byte) (uint64, int) { + var n uint64 + var size int + for _, val := range serialized { + size++ + n = (n << 7) | uint64(val&0x7f) + if val&0x80 != 0x80 { + break + } + n++ + } + + return n, size +} + +// ----------------------------------------------------------------------------- +// In order to reduce the size of stored scripts, a domain specific compression +// algorithm is used which recognizes standard scripts and stores them using +// less bytes than the original script. The compression algorithm used here was +// obtained from Bitcoin Core, so all credits for the algorithm go to it. +// +// The general serialized format is: +// +//