diff --git a/assets/assets.go b/assets/assets.go
index 10f1892..f3fed91 100644
--- a/assets/assets.go
+++ b/assets/assets.go
@@ -2,13 +2,15 @@ package assets
import (
"fmt"
+ "math"
"math/big"
"github.com/bisoncraft/utxowallet/netparams"
+ "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
)
-func NetParams(chain, net string) (p *netparams.ChainParams, _ error) {
+func NetParams(chain, net string) (p *netparams.ChainParams, err error) {
switch chain {
case "btc":
p = BTCParams[net]
@@ -18,6 +20,9 @@ func NetParams(chain, net string) (p *netparams.ChainParams, _ error) {
if p == nil {
return nil, fmt.Errorf("no net params for chain %s, network %s", chain, net)
}
+ registerParams := *p.BTCDParams() // populate the internal btcParams field
+ registerParams.Net = math.MaxUint32
+ err = chaincfg.Register(®isterParams)
return
}
diff --git a/assets/assets_test.go b/assets/assets_test.go
new file mode 100644
index 0000000..ff10cee
--- /dev/null
+++ b/assets/assets_test.go
@@ -0,0 +1,23 @@
+package assets
+
+import "testing"
+
+func TestParams(t *testing.T) {
+ for chain, nets := range map[string][]string{
+ "btc": {"mainnet", "testnet", "simnet"},
+ "ltc": {"mainnet", "testnet", "simnet"},
+ } {
+ for _, net := range nets {
+ t.Run(chain+"."+net, func(t *testing.T) {
+ chainParams, _ := NetParams(chain, net)
+ h := chainParams.GenesisBlock.BlockHash()
+ if h != *chainParams.GenesisHash {
+ t.Fatalf("Genesis hash mismatch")
+ }
+ if chainParams.Chain != chain {
+ t.Fatalf("Wrong chain. %s != %s", chainParams.Chain, chain)
+ }
+ })
+ }
+ }
+}
diff --git a/assets/btc.go b/assets/btc.go
index dbccc2f..5aaa082 100644
--- a/assets/btc.go
+++ b/assets/btc.go
@@ -22,6 +22,7 @@ var genesisMerkleRoot = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet
var BTCParams = map[string]*netparams.ChainParams{
"mainnet": {
+ Chain: "btc",
Name: "mainnet",
Net: wire.MainNet,
DefaultPort: "8333",
@@ -95,9 +96,12 @@ var BTCParams = map[string]*netparams.ChainParams{
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
}),
PowLimit: new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne),
+ PowLimitBits: 0x1d00ffff,
TargetTimespan: time.Hour * 24 * 14, // 14 days
TargetTimePerBlock: time.Minute * 10, // 10 minutes
RetargetAdjustmentFactor: 4, // 25% less, 400% more
+ ReduceMinDifficulty: false,
+ MinDiffReductionTime: 0,
// Checkpoints ordered from oldest to newest.
Checkpoints: []chaincfg.Checkpoint{
@@ -144,14 +148,17 @@ var BTCParams = map[string]*netparams.ChainParams{
WitnessPubKeyHashAddrID: 0x06, // starts with p2
WitnessScriptHashAddrID: 0x0A, // starts with 7Xh
// BIP32 hierarchical deterministic extended key magics
- HDPrivateKeyID: [4]byte{0x04, 0x88, 0xad, 0xe4}, // starts with xprv
- HDPublicKeyID: [4]byte{0x04, 0x88, 0xb2, 0x1e}, // starts with xpub
- HDCoinType: 0,
- BIP0034Height: 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8
- BIP0065Height: 388381, // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
- BIP0066Height: 363725, // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
+ HDPrivateKeyID: [4]byte{0x04, 0x88, 0xad, 0xe4}, // starts with xprv
+ HDPublicKeyID: [4]byte{0x04, 0x88, 0xb2, 0x1e}, // starts with xpub
+ HDCoinType: 0,
+ BIP0034Height: 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8
+ BIP0065Height: 388381, // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
+ BIP0066Height: 363725, // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
+ CoinbaseMaturity: 100,
+ MaxSatoshi: btcutil.MaxSatoshi,
},
"testnet": {
+ Chain: "btc",
Name: "testnet3",
Net: wire.TestNet3,
DefaultPort: "18333",
@@ -219,9 +226,12 @@ var BTCParams = map[string]*netparams.ChainParams{
0x01, 0xea, 0x33, 0x09, 0x00, 0x00, 0x00, 0x00,
}),
PowLimit: new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne),
+ PowLimitBits: 0x1d00ffff,
TargetTimespan: time.Hour * 24 * 14, // 14 days
TargetTimePerBlock: time.Minute * 10, // 10 minutes
RetargetAdjustmentFactor: 4, // 25% less, 400% more
+ ReduceMinDifficulty: true,
+ MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
// Checkpoints ordered from oldest to newest.
Checkpoints: []chaincfg.Checkpoint{
@@ -261,11 +271,14 @@ var BTCParams = map[string]*netparams.ChainParams{
BIP0034Height: 21111, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
BIP0065Height: 581885, // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
BIP0066Height: 330776, // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
+ CoinbaseMaturity: 100,
+ MaxSatoshi: btcutil.MaxSatoshi,
},
"simnet": {
+ Chain: "btc",
Name: "regtest",
Net: wire.TestNet,
- DefaultPort: "18444",
+ DefaultPort: "20575", // 18444 // Changed to match dcrdex testing harness
DNSSeeds: []chaincfg.DNSSeed{},
GenesisBlock: &wire.MsgBlock{
Header: wire.BlockHeader{
@@ -325,9 +338,13 @@ var BTCParams = map[string]*netparams.ChainParams{
0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f,
}),
PowLimit: new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne),
+ PowLimitBits: 0x207fffff,
+ PoWNoRetargeting: true,
TargetTimespan: time.Hour * 24 * 14, // 14 days
TargetTimePerBlock: time.Minute * 10, // 10 minutes
RetargetAdjustmentFactor: 4, // 25% less, 400% more
+ ReduceMinDifficulty: true,
+ MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
Checkpoints: nil,
Bech32HRPSegwit: "bcrt", // always bcrt for reg test net
PubKeyHashAddrID: 0x6f, // starts with m or n
@@ -339,6 +356,7 @@ var BTCParams = map[string]*netparams.ChainParams{
BIP0034Height: 100000000, // Not active - Permit ver 1 blocks
BIP0065Height: 1351, // Used by regression tests
BIP0066Height: 1251, // Used by regression tests
+ CoinbaseMaturity: 100,
MaxSatoshi: btcutil.MaxSatoshi,
},
}
diff --git a/assets/ltc.go b/assets/ltc.go
new file mode 100644
index 0000000..4305aea
--- /dev/null
+++ b/assets/ltc.go
@@ -0,0 +1,262 @@
+package assets
+
+import (
+ "bytes"
+ "fmt"
+ "math/big"
+ "time"
+
+ "github.com/bisoncraft/utxowallet/netparams"
+ "github.com/btcsuite/btcd/blockchain"
+ "github.com/btcsuite/btcd/btcutil"
+ "github.com/btcsuite/btcd/chaincfg"
+ "github.com/btcsuite/btcd/chaincfg/chainhash"
+ "github.com/btcsuite/btcd/wire"
+ "golang.org/x/crypto/scrypt"
+)
+
+var (
+ ltcMainPowLimit, _ = new(big.Int).SetString("0x0fffff000000000000000000000000000000000000000000000000000000", 0)
+ ltcGenesisCoinbaseTx = wire.MsgTx{
+ Version: 1,
+ TxIn: []*wire.TxIn{
+ {
+ PreviousOutPoint: wire.OutPoint{
+ Hash: chainhash.Hash{},
+ Index: 0xffffffff,
+ },
+ SignatureScript: []byte{
+ 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x40, 0x4e, 0x59, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x73, // |.......@NY Times|
+ 0x20, 0x30, 0x35, 0x2f, 0x4f, 0x63, 0x74, 0x2f, 0x32, 0x30, 0x31, 0x31, 0x20, 0x53, 0x74, 0x65, // | 05/Oct/2011 Ste|
+ 0x76, 0x65, 0x20, 0x4a, 0x6f, 0x62, 0x73, 0x2c, 0x20, 0x41, 0x70, 0x70, 0x6c, 0x65, 0xe2, 0x80, // |ve Jobs, Apple..|
+ 0x99, 0x73, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x61, 0x72, 0x79, 0x2c, 0x20, 0x44, 0x69, // |.s Visionary, Di|
+ 0x65, 0x73, 0x20, 0x61, 0x74, 0x20, 0x35, 0x36, // |es at 56|
+
+ },
+ Sequence: 0xffffffff,
+ },
+ },
+ TxOut: []*wire.TxOut{
+ {
+ Value: 0x12a05f200,
+ PkScript: []byte{
+ 0x41, 0x4, 0x1, 0x84, 0x71, 0xf, 0xa6, 0x89,
+ 0xad, 0x50, 0x23, 0x69, 0xc, 0x80, 0xf3, 0xa4,
+ 0x9c, 0x8f, 0x13, 0xf8, 0xd4, 0x5b, 0x8c, 0x85,
+ 0x7f, 0xbc, 0xbc, 0x8b, 0xc4, 0xa8, 0xe4, 0xd3,
+ 0xeb, 0x4b, 0x10, 0xf4, 0xd4, 0x60, 0x4f, 0xa0,
+ 0x8d, 0xce, 0x60, 0x1a, 0xaf, 0xf, 0x47, 0x2,
+ 0x16, 0xfe, 0x1b, 0x51, 0x85, 0xb, 0x4a, 0xcf,
+ 0x21, 0xb1, 0x79, 0xc4, 0x50, 0x70, 0xac, 0x7b,
+ 0x3, 0xa9, 0xac,
+ },
+ },
+ },
+ LockTime: 0,
+ }
+ ltcGenesisMerkleRoot = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
+ 0xd9, 0xce, 0xd4, 0xed, 0x11, 0x30, 0xf7, 0xb7,
+ 0xfa, 0xad, 0x9b, 0xe2, 0x53, 0x23, 0xff, 0xaf,
+ 0xa3, 0x32, 0x32, 0xa1, 0x7c, 0x3e, 0xdf, 0x6c,
+ 0xfd, 0x97, 0xbe, 0xe6, 0xba, 0xfb, 0xdd, 0x97,
+ })
+)
+
+var LTCParams = map[string]*netparams.ChainParams{
+ "mainnet": {
+ Chain: "ltc",
+ Name: "mainnet",
+ Net: 0xdbb6c0fb,
+ DefaultPort: "9333",
+ DNSSeeds: []chaincfg.DNSSeed{
+ {"seed-a.litecoin.loshan.co.uk", true},
+ {"dnsseed.thrasher.io", true},
+ {"dnsseed.litecointools.com", false},
+ {"dnsseed.litecoinpool.org", false},
+ },
+ GenesisBlock: &wire.MsgBlock{
+ Header: wire.BlockHeader{
+ Version: 1,
+ PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
+ MerkleRoot: ltcGenesisMerkleRoot,
+ Timestamp: time.Unix(1317972665, 0),
+ Bits: 0x1e0ffff0,
+ Nonce: 2084524493,
+ },
+ Transactions: []*wire.MsgTx{<cGenesisCoinbaseTx},
+ },
+ GenesisHash: hashPointer([chainhash.HashSize]byte{ // Make go vet happy.
+ 0xe2, 0xbf, 0x04, 0x7e, 0x7e, 0x5a, 0x19, 0x1a,
+ 0xa4, 0xef, 0x34, 0xd3, 0x14, 0x97, 0x9d, 0xc9,
+ 0x98, 0x6e, 0x0f, 0x19, 0x25, 0x1e, 0xda, 0xba,
+ 0x59, 0x40, 0xfd, 0x1f, 0xe3, 0x65, 0xa7, 0x12,
+ }),
+ PowLimit: ltcMainPowLimit,
+ PowLimitBits: 504365055,
+ TargetTimespan: (time.Hour * 24 * 3) + (time.Hour * 12), // 3.5 days
+ TargetTimePerBlock: (time.Minute * 2) + (time.Second * 30), // 2.5 minutes
+ RetargetAdjustmentFactor: 4, // 25% less, 400% more
+ ReduceMinDifficulty: false,
+ MinDiffReductionTime: 0,
+ Checkpoints: []chaincfg.Checkpoint{
+ {1500, newHashFromStr("841a2965955dd288cfa707a755d05a54e45f8bd476835ec9af4402a2b59a2967")},
+ {4032, newHashFromStr("9ce90e427198fc0ef05e5905ce3503725b80e26afd35a987965fd7e3d9cf0846")},
+ {8064, newHashFromStr("eb984353fc5190f210651f150c40b8a4bab9eeeff0b729fcb3987da694430d70")},
+ {16128, newHashFromStr("602edf1859b7f9a6af809f1d9b0e6cb66fdc1d4d9dcd7a4bec03e12a1ccd153d")},
+ {23420, newHashFromStr("d80fdf9ca81afd0bd2b2a90ac3a9fe547da58f2530ec874e978fce0b5101b507")},
+ {50000, newHashFromStr("69dc37eb029b68f075a5012dcc0419c127672adb4f3a32882b2b3e71d07a20a6")},
+ {80000, newHashFromStr("4fcb7c02f676a300503f49c764a89955a8f920b46a8cbecb4867182ecdb2e90a")},
+ {120000, newHashFromStr("bd9d26924f05f6daa7f0155f32828ec89e8e29cee9e7121b026a7a3552ac6131")},
+ {161500, newHashFromStr("dbe89880474f4bb4f75c227c77ba1cdc024991123b28b8418dbbf7798471ff43")},
+ {179620, newHashFromStr("2ad9c65c990ac00426d18e446e0fd7be2ffa69e9a7dcb28358a50b2b78b9f709")},
+ {240000, newHashFromStr("7140d1c4b4c2157ca217ee7636f24c9c73db39c4590c4e6eab2e3ea1555088aa")},
+ {383640, newHashFromStr("2b6809f094a9215bafc65eb3f110a35127a34be94b7d0590a096c3f126c6f364")},
+ {409004, newHashFromStr("487518d663d9f1fa08611d9395ad74d982b667fbdc0e77e9cf39b4f1355908a3")},
+ {456000, newHashFromStr("bf34f71cc6366cd487930d06be22f897e34ca6a40501ac7d401be32456372004")},
+ {638902, newHashFromStr("15238656e8ec63d28de29a8c75fcf3a5819afc953dcd9cc45cecc53baec74f38")},
+ {721000, newHashFromStr("198a7b4de1df9478e2463bd99d75b714eab235a2e63e741641dc8a759a9840e5")},
+ },
+ Bech32HRPSegwit: "ltc", // always ltc for main net
+ PubKeyHashAddrID: 0x30, // starts with L
+ ScriptHashAddrID: 0x32, // starts with M
+ PrivateKeyID: 0xB0, // starts with 6 (uncompressed) or T (compressed)
+ WitnessPubKeyHashAddrID: 0x06, // starts with p2
+ WitnessScriptHashAddrID: 0x0A, // starts with 7Xh
+ HDPrivateKeyID: [4]byte{0x04, 0x88, 0xad, 0xe4}, // starts with xprv
+ HDPublicKeyID: [4]byte{0x04, 0x88, 0xb2, 0x1e}, // starts with xpub
+ HDCoinType: 2,
+ BIP0034Height: 710000,
+ BIP0065Height: 918684,
+ BIP0066Height: 811879,
+ CheckPoW: checkPoWScrypt,
+ CoinbaseMaturity: 100,
+ MaxSatoshi: 84e6 * btcutil.SatoshiPerBitcoin,
+ },
+ "testnet": {
+ Chain: "ltc",
+ Name: "testnet4",
+ Net: 0xf1c8d2fd,
+ DefaultPort: "19335",
+ DNSSeeds: []chaincfg.DNSSeed{
+ {"testnet-seed.litecointools.com", false},
+ {"seed-b.litecoin.loshan.co.uk", false /*true*/},
+ {"dnsseed-testnet.thrasher.io", false /*true*/},
+ },
+ GenesisBlock: &wire.MsgBlock{
+ Header: wire.BlockHeader{
+ Version: 1,
+ PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
+ MerkleRoot: ltcGenesisMerkleRoot,
+ Timestamp: time.Unix(1486949366, 0),
+ Bits: 0x1e0ffff0,
+ Nonce: 293345,
+ },
+ Transactions: []*wire.MsgTx{<cGenesisCoinbaseTx},
+ },
+ GenesisHash: hashPointer([chainhash.HashSize]byte{ // Make go vet happy.
+ 0xa0, 0x29, 0x3e, 0x4e, 0xeb, 0x3d, 0xa6, 0xe6,
+ 0xf5, 0x6f, 0x81, 0xed, 0x59, 0x5f, 0x57, 0x88,
+ 0xd, 0x1a, 0x21, 0x56, 0x9e, 0x13, 0xee, 0xfd,
+ 0xd9, 0x51, 0x28, 0x4b, 0x5a, 0x62, 0x66, 0x49,
+ }),
+ PowLimit: ltcMainPowLimit,
+ PowLimitBits: 504365055,
+ BIP0034Height: 76,
+ BIP0065Height: 76,
+ BIP0066Height: 76,
+ TargetTimespan: (time.Hour * 24 * 3) + (time.Hour * 12), // 3.5 days
+ TargetTimePerBlock: (time.Minute * 2) + (time.Second * 30), // 2.5 minutes
+ RetargetAdjustmentFactor: 4,
+ ReduceMinDifficulty: true,
+ MinDiffReductionTime: time.Minute * 5, // TargetTimePerBlock * 2
+ Checkpoints: []chaincfg.Checkpoint{
+ {26115, newHashFromStr("817d5b509e91ab5e439652eee2f59271bbc7ba85021d720cdb6da6565b43c14f")},
+ {43928, newHashFromStr("7d86614c153f5ef6ad878483118ae523e248cd0dd0345330cb148e812493cbb4")},
+ {69296, newHashFromStr("66c2f58da3cfd282093b55eb09c1f5287d7a18801a8ff441830e67e8771010df")},
+ {99949, newHashFromStr("8dd471cb5aecf5ead91e7e4b1e932c79a0763060f8d93671b6801d115bfc6cde")},
+ {159256, newHashFromStr("ab5b0b9968842f5414804591119d6db829af606864b1959a25d6f5c114afb2b7")},
+ {2394367, newHashFromStr("bc5829f4973d0797755efee11313687b3c63ee2f70b60b62eebcd10283534327")},
+ },
+ Bech32HRPSegwit: "tltc", // always tltc for test net
+ PubKeyHashAddrID: 0x6f, // starts with m or n
+ ScriptHashAddrID: 0x3a, // starts with Q
+ WitnessPubKeyHashAddrID: 0x52, // starts with QW
+ WitnessScriptHashAddrID: 0x31, // starts with T7n
+ PrivateKeyID: 0xef, // starts with 9 (uncompressed) or c (compressed)
+ HDPrivateKeyID: [4]byte{0x04, 0x35, 0x83, 0x94}, // starts with tprv
+ HDPublicKeyID: [4]byte{0x04, 0x35, 0x87, 0xcf}, // starts with tpub
+ HDCoinType: 1,
+ CheckPoW: checkPoWScrypt,
+ CoinbaseMaturity: 100,
+ MaxSatoshi: 84e6 * btcutil.SatoshiPerBitcoin,
+ },
+ "simnet": {
+ Chain: "ltc",
+ Name: "regtest",
+ Net: 0xdab5bffa,
+ DefaultPort: "19444",
+ DNSSeeds: []chaincfg.DNSSeed{},
+
+ // Chain parameters
+ GenesisBlock: &wire.MsgBlock{
+ Header: wire.BlockHeader{
+ Version: 1,
+ PrevBlock: chainhash.Hash{},
+ MerkleRoot: ltcGenesisMerkleRoot,
+ Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC
+ Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000]
+ Nonce: 0,
+ },
+ Transactions: []*wire.MsgTx{<cGenesisCoinbaseTx},
+ },
+ GenesisHash: hashPointer([chainhash.HashSize]byte{ // Make go vet happy.
+ 0xf9, 0x16, 0xc4, 0x56, 0xfc, 0x51, 0xdf, 0x62,
+ 0x78, 0x85, 0xd7, 0xd6, 0x74, 0xed, 0x02, 0xdc,
+ 0x88, 0xa2, 0x25, 0xad, 0xb3, 0xf0, 0x2a, 0xd1,
+ 0x3e, 0xb4, 0x93, 0x8f, 0xf3, 0x27, 0x08, 0x53,
+ }),
+ PowLimit: new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne),
+ PowLimitBits: 0x207fffff,
+ PoWNoRetargeting: true,
+ BIP0034Height: 100000000, // Not active - Permit ver 1 blocks
+ BIP0065Height: 1351, // Used by regression tests
+ BIP0066Height: 1251, // Used by regression tests
+ TargetTimespan: (time.Hour * 24 * 3) + (time.Hour * 12), // 3.5 days
+ TargetTimePerBlock: (time.Minute * 2) + (time.Second * 30), // 2.5 minutes
+ RetargetAdjustmentFactor: 4, // 25% less, 400% more
+ ReduceMinDifficulty: true,
+ MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
+
+ // Checkpoints ordered from oldest to newest.
+ Checkpoints: nil,
+ Bech32HRPSegwit: "rltc", // always rltc for reg test net
+ PubKeyHashAddrID: 0x6f, // starts with m or n
+ ScriptHashAddrID: 0x3a, // starts with Q
+ PrivateKeyID: 0xef, // starts with 9 (uncompressed) or c (compressed)
+ HDPrivateKeyID: [4]byte{0x04, 0x35, 0x83, 0x94}, // starts with tprv
+ HDPublicKeyID: [4]byte{0x04, 0x35, 0x87, 0xcf}, // starts with tpub
+ HDCoinType: 1,
+ CheckPoW: checkPoWScrypt,
+ CoinbaseMaturity: 100,
+ MaxSatoshi: 84e6 * btcutil.SatoshiPerBitcoin,
+ },
+}
+
+func checkPoWScrypt(hdr *wire.BlockHeader) error {
+ var powHash chainhash.Hash
+
+ buf := bytes.NewBuffer(make([]byte, 0, wire.MaxBlockHeaderPayload))
+ hdr.Serialize(buf)
+
+ scryptHash, _ := scrypt.Key(buf.Bytes(), buf.Bytes(), 1024, 1, 1, 32)
+ copy(powHash[:], scryptHash)
+
+ target := blockchain.CompactToBig(hdr.Bits)
+
+ hashNum := blockchain.HashToBig(&powHash)
+ if hashNum.Cmp(target) > 0 {
+ return fmt.Errorf("block hash of %064x is higher than "+
+ "expected max of %064x", hashNum, target)
+ }
+ return nil
+}
diff --git a/bisonwire/bisonwire.go b/bisonwire/bisonwire.go
index 1025f02..beb5236 100644
--- a/bisonwire/bisonwire.go
+++ b/bisonwire/bisonwire.go
@@ -38,13 +38,13 @@ func makeEmptyMessage(chain Chain, command string) (wire.Message, error) {
msg = &wire.MsgGetBlocks{}
case wire.CmdBlock:
- msg = &wire.MsgBlock{}
+ msg = &Block{Chain: string(chain)}
case wire.CmdHeaders:
msg = &wire.MsgHeaders{}
case wire.CmdTx:
- msg = &wire.MsgTx{}
+ msg = &Tx{Chain: string(chain)}
// Standard BTC wire types
case wire.CmdVersion:
@@ -129,7 +129,7 @@ func makeEmptyMessage(chain Chain, command string) (wire.Message, error) {
msg = &wire.MsgCFCheckpt{}
default:
- return nil, wire.ErrUnknownMessage
+ return nil, fmt.Errorf("%w: %s", wire.ErrUnknownMessage, command)
}
return msg, nil
}
diff --git a/bisonwire/block.go b/bisonwire/block.go
new file mode 100644
index 0000000..7af20dd
--- /dev/null
+++ b/bisonwire/block.go
@@ -0,0 +1,98 @@
+package bisonwire
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/btcsuite/btcd/wire"
+)
+
+// Block is a wire.MsgBlock, but with *bisonwire.Tx instead of wire.MsgTx.
+type Block struct {
+ Chain string
+ Header wire.BlockHeader
+ Transactions []*Tx
+}
+
+// MsgBlock generates a *wire.MsgBlock from the *Block.
+func (b *Block) MsgBlock() *wire.MsgBlock {
+ msgBlock := &wire.MsgBlock{
+ Header: b.Header,
+ Transactions: make([]*wire.MsgTx, len(b.Transactions)),
+ }
+ for i, tx := range b.Transactions {
+ msgBlock.Transactions[i] = &tx.MsgTx
+ }
+ return msgBlock
+}
+
+// BlockFromMsgBlock generates a *Block, with a *wire.MsgBlock as it's base. The
+// wire.MsgTx's are converted to *Tx. This is only used in tests for now, So we
+// can ignore the additional Tx fields that aren't contained in *wire.MsgBlock.
+func BlockFromMsgBlock(chain string, msgBlock *wire.MsgBlock) *Block {
+ blk := &Block{
+ Chain: chain,
+ Header: msgBlock.Header,
+ Transactions: make([]*Tx, len(msgBlock.Transactions)),
+ }
+ for i, msgTx := range msgBlock.Transactions {
+ blk.Transactions[i] = &Tx{
+ MsgTx: *msgTx,
+ Chain: chain,
+ }
+ }
+ return blk
+}
+
+// BtcDecode decodes the serialized block based on the Block's Chain.
+func (b *Block) BtcDecode(r io.Reader, pver uint32, enc wire.MessageEncoding) error {
+ switch b.Chain {
+ case "btc":
+ var msgBlock wire.MsgBlock
+ if err := msgBlock.BtcDecode(r, pver, enc); err != nil {
+ return fmt.Errorf("error decoding Bitcoin block: %w", err)
+ }
+ b.Header = msgBlock.Header
+ b.Transactions = make([]*Tx, len(msgBlock.Transactions))
+ for i, msgTx := range msgBlock.Transactions {
+ b.Transactions[i] = &Tx{
+ MsgTx: *msgTx,
+ Chain: b.Chain,
+ }
+ }
+ case "ltc":
+ blk, err := deserializeLitecoinBlock(r)
+ if err != nil {
+ return fmt.Errorf("error decoding Litecoin Bitcoin block: %w", err)
+ }
+ b.Header = blk.Header
+ b.Transactions = blk.Transactions
+ default:
+ return fmt.Errorf("unknown chain %q specified for block decoding", b.Chain)
+ }
+ return nil
+}
+
+func (b *Block) BtcEncode(r io.Writer, pver uint32, enc wire.MessageEncoding) error {
+ switch b.Chain {
+ case "btc":
+ return b.MsgBlock().BtcEncode(r, pver, enc)
+ case "ltc":
+ panic("bisonwire block encoding not implemented for Litecoin") // I don't think we ever use this
+ default:
+ return fmt.Errorf("unknown chain %q specified for block decoding", b.Chain)
+ }
+}
+
+func (b *Block) Command() string {
+ return wire.CmdBlock
+}
+
+func (b *Block) MaxPayloadLength(uint32) uint32 {
+ return wire.MaxBlockPayload
+}
+
+type BlockWithHeight struct {
+ Block *Block
+ Height uint32
+}
diff --git a/bisonwire/decoder.go b/bisonwire/decoder.go
new file mode 100644
index 0000000..042a8ac
--- /dev/null
+++ b/bisonwire/decoder.go
@@ -0,0 +1,404 @@
+package bisonwire
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io"
+
+ "github.com/btcsuite/btcd/wire"
+)
+
+var byteOrder = binary.LittleEndian
+
+const (
+ pver uint32 = 0 // only protocol version 0 supported
+ maxTxInPerMessage = wire.MaxMessagePayload/41 + 1 // wire.maxTxInPerMessage
+ maxTxOutPerMessage = wire.MaxMessagePayload/ // wire.maxTxOutPerMessage
+ wire.MinTxOutPayload + 1
+ maxWitnessItemsPerInput = 4_000_000 // from wire
+ maxWitnessItemSize = 4_000_000 // from wire
+)
+
+type decoder struct {
+ buf [8]byte
+ rd io.Reader
+ tee *bytes.Buffer // anything read from rd is Written to tee
+}
+
+func newDecoder(r io.Reader) *decoder {
+ return &decoder{rd: r}
+}
+
+func (d *decoder) Read(b []byte) (n int, err error) {
+ n, err = d.rd.Read(b)
+ if err != nil {
+ return 0, err
+ }
+ if d.tee != nil {
+ d.tee.Write(b)
+ }
+ return n, nil
+}
+
+func (d *decoder) readByte() (byte, error) {
+ b := d.buf[:1]
+ if _, err := io.ReadFull(d, b); err != nil {
+ return 0, err
+ }
+ return b[0], nil
+}
+
+func (d *decoder) readUint16() (uint16, error) {
+ b := d.buf[:2]
+ if _, err := io.ReadFull(d, b); err != nil {
+ return 0, err
+ }
+ return byteOrder.Uint16(b), nil
+}
+
+func (d *decoder) readUint32() (uint32, error) {
+ b := d.buf[:4]
+ if _, err := io.ReadFull(d, b); err != nil {
+ return 0, err
+ }
+ return byteOrder.Uint32(b), nil
+}
+
+func (d *decoder) readUint64() (uint64, error) {
+ b := d.buf[:]
+ if _, err := io.ReadFull(d, b); err != nil {
+ return 0, err
+ }
+ return byteOrder.Uint64(b), nil
+}
+
+// readOutPoint reads the next sequence of bytes from r as an OutPoint.
+func (d *decoder) readOutPoint(op *wire.OutPoint) error {
+ _, err := io.ReadFull(d, op.Hash[:])
+ if err != nil {
+ return err
+ }
+
+ op.Index, err = d.readUint32()
+ return err
+}
+
+// wire.ReadVarInt a.k.a. CompactSize, not VARINT
+// https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
+func (d *decoder) readCompactSize() (uint64, error) {
+ // Compact Size
+ // size < 253 -- 1 byte
+ // size <= USHRT_MAX -- 3 bytes (253 + 2 bytes)
+ // size <= UINT_MAX -- 5 bytes (254 + 4 bytes)
+ // size > UINT_MAX -- 9 bytes (255 + 8 bytes)
+ chSize, err := d.readByte()
+ if err != nil {
+ return 0, err
+ }
+ switch chSize {
+ case 253:
+ sz, err := d.readUint16()
+ if err != nil {
+ return 0, err
+ }
+ return uint64(sz), nil
+ case 254:
+ sz, err := d.readUint32()
+ if err != nil {
+ return 0, err
+ }
+ return uint64(sz), nil
+ case 255:
+ sz, err := d.readUint64()
+ if err != nil {
+ return 0, err
+ }
+ return sz, nil
+ default: // < 253
+ return uint64(chSize), nil
+ }
+}
+
+// variable length quantity, not supposed to be part of the wire protocol.
+// Not the same as CompactSize type in the C++ code, but rather VARINT.
+// https://en.wikipedia.org/wiki/Variable-length_quantity
+// This function is borrowed from dcrd.
+func (d *decoder) readVLQ() (uint64, error) {
+ var n uint64
+ for {
+ val, err := d.readByte()
+ if err != nil {
+ return 0, err
+ }
+ n = (n << 7) | uint64(val&0x7f)
+ if val&0x80 != 0x80 {
+ break
+ }
+ n++
+ }
+
+ return n, nil
+}
+
+// readTxIn reads the next sequence of bytes from r as a transaction input.
+func (d *decoder) readTxIn(ti *wire.TxIn) error {
+ err := d.readOutPoint(&ti.PreviousOutPoint)
+ if err != nil {
+ return err
+ }
+
+ ti.SignatureScript, err = wire.ReadVarBytes(d, pver, wire.MaxMessagePayload, "sigScript")
+ if err != nil {
+ return err
+ }
+
+ ti.Sequence, err = d.readUint32()
+ return err
+}
+
+// readTxOut reads the next sequence of bytes from r as a transaction output.
+func (d *decoder) readTxOut(to *wire.TxOut) error {
+ v, err := d.readUint64()
+ if err != nil {
+ return err
+ }
+
+ pkScript, err := wire.ReadVarBytes(d, pver, wire.MaxMessagePayload, "pkScript")
+ if err != nil {
+ return err
+ }
+
+ to.Value = int64(v)
+ to.PkScript = pkScript
+
+ return nil
+}
+
+func (d *decoder) discardBytes(n int64) error {
+ m, err := io.CopyN(io.Discard, d, n)
+ if err != nil {
+ return err
+ }
+ if m != n {
+ return fmt.Errorf("only discarded %d of %d bytes", m, n)
+ }
+ return nil
+}
+
+func (d *decoder) discardVect() error {
+ sz, err := d.readCompactSize()
+ if err != nil {
+ return err
+ }
+ return d.discardBytes(int64(sz))
+}
+
+func (d *decoder) readMWTX() ([]byte, bool, error) {
+ // src/mweb/mweb_models.h - struct Tx
+ // "A convenience wrapper around a possibly-null MWEB transcation."
+ // Read the uint8_t is_set of OptionalPtr.
+ haveMWTX, err := d.readByte()
+ if err != nil {
+ return nil, false, err
+ }
+ if haveMWTX == 0 {
+ return nil, true, nil // HogEx - that's all folks
+ }
+
+ // src/libmw/include/mw/models/tx/Transaction.h - class Transaction
+ // READWRITE(obj.m_kernelOffset); // class BlindingFactor
+ // READWRITE(obj.m_stealthOffset); // class BlindingFactor
+ // READWRITE(obj.m_body); // class TxBody
+
+ // src/libmw/include/mw/models/crypto/BlindingFactor.h - class BlindingFactor
+ // just 32 bytes:
+ // BigInt<32> m_value;
+ // READWRITE(obj.m_value);
+ // x2 for both kernel_offset and stealth_offset BlindingFactor
+ if err = d.discardBytes(64); err != nil {
+ return nil, false, err
+ }
+
+ // TxBody
+ kern0, err := d.readMWTXBody()
+ if err != nil {
+ return nil, false, err
+ }
+ return kern0, false, nil
+}
+
+func (d *decoder) readMWTXBody() ([]byte, error) {
+ // src/libmw/include/mw/models/tx/TxBody.h - class TxBody
+ // READWRITE(obj.m_inputs, obj.m_outputs, obj.m_kernels);
+ // std::vector m_inputs;
+ // std::vector