diff --git a/Gopkg.lock b/Gopkg.lock index f9a70817..2f5175a9 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -61,12 +61,6 @@ revision = "1d4478f51bed434f1dadf96dcd9b43aabac66795" version = "v1.7" -[[projects]] - branch = "master" - name = "github.com/erikdubbelboer/gspt" - packages = ["."] - revision = "e39e726e09cc23d1ccf13b36ce10dbdb4a4510e0" - [[projects]] name = "github.com/ethereum/go-ethereum" packages = [".","common","common/hexutil","common/math","core/types","crypto","crypto/secp256k1","crypto/sha3","ethclient","ethdb","log","metrics","p2p/netutil","params","rlp","rpc","trie"] @@ -103,18 +97,6 @@ packages = ["."] revision = "553a641470496b2327abcac10b36396bd98e45c9" -[[projects]] - name = "github.com/gorilla/context" - packages = ["."] - revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a" - version = "v1.1" - -[[projects]] - name = "github.com/gorilla/mux" - packages = ["."] - revision = "53c1911da2b537f792e7cafcb446b05ffe33b996" - version = "v1.6.1" - [[projects]] name = "github.com/gorilla/websocket" packages = ["."] @@ -131,7 +113,7 @@ branch = "master" name = "github.com/jakm/btcutil" packages = [".","base58","bech32","chaincfg","txscript"] - revision = "a45c5a6a9cb32f0caecb14a4e5a8f82640be1f39" + revision = "c50a69d8979c23daad1728b3574c6f20691174f7" [[projects]] branch = "master" @@ -235,12 +217,6 @@ packages = ["websocket"] revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41" -[[projects]] - name = "gopkg.in/fatih/set.v0" - packages = ["."] - revision = "57907de300222151a123d29255ed17f5ed43fad3" - version = "v0.1.0" - [[projects]] branch = "v2" name = "gopkg.in/karalabe/cookiejar.v2" @@ -256,6 +232,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "98fb9a6252acd86d1c0a4b09a42e34673c2ccd6327caf49ed85bcee573601d95" + inputs-digest = "7cb7ad84fe0b30276bb7775d85c4f3281acddb12cb2e10ea4d80198981c9f80b" solver-name = "gps-cdcl" solver-version = 1 diff --git a/bchain/coins/bch/bcashparser.go b/bchain/coins/bch/bcashparser.go index 1348619d..033af920 100644 --- a/bchain/coins/bch/bcashparser.go +++ b/bchain/coins/bch/bcashparser.go @@ -25,6 +25,23 @@ const ( RegTestPrefix = "bchreg:" ) +var ( + MainNetParams chaincfg.Params + TestNetParams chaincfg.Params + RegtestParams chaincfg.Params +) + +func init() { + MainNetParams = chaincfg.MainNetParams + MainNetParams.Net = bchutil.MainnetMagic + + TestNetParams = chaincfg.TestNet3Params + TestNetParams.Net = bchutil.TestnetMagic + + RegtestParams = chaincfg.RegressionNetParams + RegtestParams.Net = bchutil.Regtestmagic +} + // BCashParser handle type BCashParser struct { *btc.BitcoinParser @@ -62,17 +79,26 @@ func NewBCashParser(params *chaincfg.Params, c *btc.Configuration) (*BCashParser // the regression test Bitcoin Cash network, the test Bitcoin Cash network and // the simulation test Bitcoin Cash network, in this order func GetChainParams(chain string) *chaincfg.Params { + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err == nil { + err = chaincfg.Register(&TestNetParams) + } + if err == nil { + err = chaincfg.Register(&RegtestParams) + } + if err != nil { + panic(err) + } + } var params *chaincfg.Params switch chain { case "test": - params = &chaincfg.TestNet3Params - params.Net = bchutil.TestnetMagic + return &TestNetParams case "regtest": - params = &chaincfg.RegressionNetParams - params.Net = bchutil.Regtestmagic + return &RegtestParams default: - params = &chaincfg.MainNetParams - params.Net = bchutil.MainnetMagic + return &MainNetParams } return params diff --git a/bchain/coins/bch/bcashparser_test.go b/bchain/coins/bch/bcashparser_test.go index 71464b57..b349911c 100644 --- a/bchain/coins/bch/bcashparser_test.go +++ b/bchain/coins/bch/bcashparser_test.go @@ -7,10 +7,19 @@ import ( "blockbook/bchain/coins/btc" "encoding/hex" "math/big" + "os" "reflect" "testing" + + "github.com/jakm/btcutil/chaincfg" ) +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + func Test_GetAddrDescFromAddress(t *testing.T) { mainParserCashAddr, mainParserLegacy, testParserCashAddr, _ := setupParsers(t) tests := []struct { diff --git a/bchain/coins/btc/bitcoinparser.go b/bchain/coins/btc/bitcoinparser.go index 41f9f2ad..cb27442e 100644 --- a/bchain/coins/btc/bitcoinparser.go +++ b/bchain/coins/btc/bitcoinparser.go @@ -42,6 +42,9 @@ func NewBitcoinParser(params *chaincfg.Params, c *Configuration) *BitcoinParser // the regression test Bitcoin network, the test Bitcoin network and // the simulation test Bitcoin network, in this order func GetChainParams(chain string) *chaincfg.Params { + if !chaincfg.IsRegistered(&chaincfg.MainNetParams) { + chaincfg.RegisterBitcoinParams() + } switch chain { case "test": return &chaincfg.TestNet3Params diff --git a/bchain/coins/btc/bitcoinparser_test.go b/bchain/coins/btc/bitcoinparser_test.go index 80245180..eef8b02c 100644 --- a/bchain/coins/btc/bitcoinparser_test.go +++ b/bchain/coins/btc/bitcoinparser_test.go @@ -6,10 +6,19 @@ import ( "blockbook/bchain" "encoding/hex" "math/big" + "os" "reflect" "testing" + + "github.com/jakm/btcutil/chaincfg" ) +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + func Test_GetAddrDescFromAddress(t *testing.T) { type args struct { address string diff --git a/bchain/coins/btg/bgoldparser.go b/bchain/coins/btg/bgoldparser.go index 1e87aa93..a2a06127 100644 --- a/bchain/coins/btg/bgoldparser.go +++ b/bchain/coins/btg/bgoldparser.go @@ -23,7 +23,7 @@ var ( TestNetParams chaincfg.Params ) -func initParams() { +func init() { MainNetParams = chaincfg.MainNetParams MainNetParams.Net = MainnetMagic @@ -39,14 +39,6 @@ func initParams() { // see https://github.com/satoshilabs/slips/blob/master/slip-0173.md MainNetParams.Bech32HRPSegwit = "btg" TestNetParams.Bech32HRPSegwit = "tbtg" - - err := chaincfg.Register(&MainNetParams) - if err == nil { - err = chaincfg.Register(&TestNetParams) - } - if err != nil { - panic(err) - } } // BGoldParser handle @@ -63,8 +55,14 @@ func NewBGoldParser(params *chaincfg.Params, c *btc.Configuration) *BGoldParser // the regression test Bitcoin Cash network, the test Bitcoin Cash network and // the simulation test Bitcoin Cash network, in this order func GetChainParams(chain string) *chaincfg.Params { - if MainNetParams.Name == "" { - initParams() + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err == nil { + err = chaincfg.Register(&TestNetParams) + } + if err != nil { + panic(err) + } } switch chain { case "test": diff --git a/bchain/coins/btg/bgoldparser_test.go b/bchain/coins/btg/bgoldparser_test.go index e37fecd7..4a6ed6ed 100644 --- a/bchain/coins/btg/bgoldparser_test.go +++ b/bchain/coins/btg/bgoldparser_test.go @@ -8,10 +8,19 @@ import ( "encoding/hex" "fmt" "io/ioutil" + "os" "path/filepath" "testing" + + "github.com/jakm/btcutil/chaincfg" ) +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + type testBlock struct { size int time int64 diff --git a/bchain/coins/dash/dashparser.go b/bchain/coins/dash/dashparser.go index d2371ef5..e70af2f9 100644 --- a/bchain/coins/dash/dashparser.go +++ b/bchain/coins/dash/dashparser.go @@ -19,7 +19,7 @@ var ( RegtestParams chaincfg.Params ) -func initParams() { +func init() { MainNetParams = chaincfg.MainNetParams MainNetParams.Net = MainnetMagic @@ -40,17 +40,6 @@ func initParams() { // Address encoding magics RegtestParams.PubKeyHashAddrID = []byte{140} // base58 prefix: y RegtestParams.ScriptHashAddrID = []byte{19} // base58 prefix: 8 or 9 - - err := chaincfg.Register(&MainNetParams) - if err == nil { - err = chaincfg.Register(&TestNetParams) - } - if err == nil { - err = chaincfg.Register(&RegtestParams) - } - if err != nil { - panic(err) - } } // DashParser handle @@ -67,8 +56,17 @@ func NewDashParser(params *chaincfg.Params, c *btc.Configuration) *DashParser { // the regression test Dash network, the test Dash network and // the simulation test Dash network, in this order func GetChainParams(chain string) *chaincfg.Params { - if MainNetParams.Name == "" { - initParams() + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err == nil { + err = chaincfg.Register(&TestNetParams) + } + if err == nil { + err = chaincfg.Register(&RegtestParams) + } + if err != nil { + panic(err) + } } switch chain { case "test": diff --git a/bchain/coins/dogecoin/dogecoinparser.go b/bchain/coins/dogecoin/dogecoinparser.go index 56c95983..9c115f8c 100644 --- a/bchain/coins/dogecoin/dogecoinparser.go +++ b/bchain/coins/dogecoin/dogecoinparser.go @@ -18,16 +18,11 @@ var ( MainNetParams chaincfg.Params ) -func initParams() { +func init() { MainNetParams = chaincfg.MainNetParams MainNetParams.Net = MainnetMagic MainNetParams.PubKeyHashAddrID = []byte{30} MainNetParams.ScriptHashAddrID = []byte{22} - - err := chaincfg.Register(&MainNetParams) - if err != nil { - panic(err) - } } // DogecoinParser handle @@ -43,8 +38,11 @@ func NewDogecoinParser(params *chaincfg.Params, c *btc.Configuration) *DogecoinP // GetChainParams contains network parameters for the main Dogecoin network, // and the test Dogecoin network func GetChainParams(chain string) *chaincfg.Params { - if MainNetParams.Name == "" { - initParams() + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err != nil { + panic(err) + } } switch chain { default: diff --git a/bchain/coins/dogecoin/dogecoinparser_test.go b/bchain/coins/dogecoin/dogecoinparser_test.go index 5638f664..f82ae434 100644 --- a/bchain/coins/dogecoin/dogecoinparser_test.go +++ b/bchain/coins/dogecoin/dogecoinparser_test.go @@ -10,11 +10,20 @@ import ( "fmt" "io/ioutil" "math/big" + "os" "path/filepath" "reflect" "testing" + + "github.com/jakm/btcutil/chaincfg" ) +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + func Test_GetAddrDescFromAddress_Mainnet(t *testing.T) { type args struct { address string diff --git a/bchain/coins/eth/ethrpc.go b/bchain/coins/eth/ethrpc.go index 83be98bf..6bdda516 100644 --- a/bchain/coins/eth/ethrpc.go +++ b/bchain/coins/eth/ethrpc.go @@ -48,6 +48,7 @@ type EthereumRPC struct { Mempool *bchain.NonUTXOMempool bestHeaderMu sync.Mutex bestHeader *ethtypes.Header + bestHeaderTime time.Time chanNewBlock chan *ethtypes.Header newBlockSubscription *rpc.ClientSubscription chanNewTx chan ethcommon.Hash @@ -96,6 +97,7 @@ func NewEthereumRPC(config json.RawMessage, pushHandler func(bchain.Notification // update best header to the new header s.bestHeaderMu.Lock() s.bestHeader = h + s.bestHeaderTime = time.Now() s.bestHeaderMu.Unlock() // notify blockbook pushHandler(bchain.NotificationNewBlock) @@ -188,7 +190,7 @@ func (b *EthereumRPC) Initialize() error { return nil } -// subscribeNewBlocks subscribes to new blocks notification +// subscribe subscribes notification and tries to resubscribe in case of error func (b *EthereumRPC) subscribe(f func() (*rpc.ClientSubscription, error)) error { s, err := f() if err != nil { @@ -281,6 +283,12 @@ func (b *EthereumRPC) GetChainInfo() (*bchain.ChainInfo, error) { func (b *EthereumRPC) getBestHeader() (*ethtypes.Header, error) { b.bestHeaderMu.Lock() defer b.bestHeaderMu.Unlock() + // ETC does not have newBlocks subscription, bestHeader must be updated very often (each 1 second) + if b.isETC { + if b.bestHeaderTime.Add(1 * time.Second).Before(time.Now()) { + b.bestHeader = nil + } + } if b.bestHeader == nil { var err error ctx, cancel := context.WithTimeout(context.Background(), b.timeout) @@ -289,6 +297,7 @@ func (b *EthereumRPC) getBestHeader() (*ethtypes.Header, error) { if err != nil { return nil, err } + b.bestHeaderTime = time.Now() } return b.bestHeader, nil } diff --git a/bchain/coins/litecoin/litecoinparser.go b/bchain/coins/litecoin/litecoinparser.go index 7a60d2ac..88d217e8 100644 --- a/bchain/coins/litecoin/litecoinparser.go +++ b/bchain/coins/litecoin/litecoinparser.go @@ -18,7 +18,7 @@ var ( TestNetParams chaincfg.Params ) -func initParams() { +func init() { MainNetParams = chaincfg.MainNetParams MainNetParams.Net = MainnetMagic MainNetParams.PubKeyHashAddrID = []byte{48} @@ -30,14 +30,6 @@ func initParams() { TestNetParams.PubKeyHashAddrID = []byte{111} TestNetParams.ScriptHashAddrID = []byte{58} TestNetParams.Bech32HRPSegwit = "tltc" - - err := chaincfg.Register(&MainNetParams) - if err == nil { - err = chaincfg.Register(&TestNetParams) - } - if err != nil { - panic(err) - } } // LitecoinParser handle @@ -53,8 +45,17 @@ func NewLitecoinParser(params *chaincfg.Params, c *btc.Configuration) *LitecoinP // GetChainParams contains network parameters for the main Litecoin network, // and the test Litecoin network func GetChainParams(chain string) *chaincfg.Params { - if MainNetParams.Name == "" { - initParams() + if !chaincfg.IsRegistered(&chaincfg.MainNetParams) { + chaincfg.RegisterBitcoinParams() + } + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err == nil { + err = chaincfg.Register(&TestNetParams) + } + if err != nil { + panic(err) + } } switch chain { case "test": diff --git a/bchain/coins/litecoin/litecoinparser_test.go b/bchain/coins/litecoin/litecoinparser_test.go index 1e046bcd..2ab4744f 100644 --- a/bchain/coins/litecoin/litecoinparser_test.go +++ b/bchain/coins/litecoin/litecoinparser_test.go @@ -7,10 +7,19 @@ import ( "blockbook/bchain/coins/btc" "encoding/hex" "math/big" + "os" "reflect" "testing" + + "github.com/jakm/btcutil/chaincfg" ) +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + func Test_GetAddrDescFromAddress_Testnet(t *testing.T) { type args struct { address string @@ -28,17 +37,29 @@ func Test_GetAddrDescFromAddress_Testnet(t *testing.T) { wantErr: false, }, { - name: "P2SH1", + name: "P2SH1-legacy", args: args{address: "2MvGVySztevmycxrSmMRjJaVj2iJin7qpap"}, want: "a9142126232e3f47ae0f1246ec5f05fc400d83c86a0d87", wantErr: false, }, { - name: "P2SH2", + name: "P2SH2-legacy", args: args{address: "2N9a2TNzWz1FEKGFxUdMEh62V83URdZ5QAZ"}, want: "a914b31049e7ee51501fe19e3e0cdb803dc84cf99f9e87", wantErr: false, }, + { + name: "P2SH1", + args: args{address: "QPdG6Ts8g2q4m9cVPTTkPGwAB6kYgXB7Hc"}, + want: "a9142126232e3f47ae0f1246ec5f05fc400d83c86a0d87", + wantErr: false, + }, + { + name: "P2SH2", + args: args{address: "QcvnaPrm17JKTT216jPFmnTvGRvFX2fWzN"}, + want: "a914b31049e7ee51501fe19e3e0cdb803dc84cf99f9e87", + wantErr: false, + }, } parser := NewLitecoinParser(GetChainParams("test"), &btc.Configuration{}) diff --git a/bchain/coins/monacoin/monacoinparser.go b/bchain/coins/monacoin/monacoinparser.go index d5a9de37..d459cd22 100644 --- a/bchain/coins/monacoin/monacoinparser.go +++ b/bchain/coins/monacoin/monacoinparser.go @@ -26,7 +26,7 @@ var ( MonaTestParams monacoinCfg.Params ) -func initParams() { +func init() { MainNetParams = chaincfg.MainNetParams MainNetParams.Net = MainnetMagic MainNetParams.PubKeyHashAddrID = []byte{50} @@ -48,14 +48,6 @@ func initParams() { MonaTestParams.PubKeyHashAddrID = 111 MonaTestParams.ScriptHashAddrID = 117 MonaTestParams.Bech32HRPSegwit = "tmona" - - err := chaincfg.Register(&MainNetParams) - if err == nil { - err = chaincfg.Register(&TestNetParams) - } - if err != nil { - panic(err) - } } // MonacoinParser handle @@ -65,14 +57,22 @@ type MonacoinParser struct { // NewMonacoinParser returns new MonacoinParser instance func NewMonacoinParser(params *chaincfg.Params, c *btc.Configuration) *MonacoinParser { - return &MonacoinParser{BitcoinParser: btc.NewBitcoinParser(params, c)} + p := &MonacoinParser{BitcoinParser: btc.NewBitcoinParser(params, c)} + p.OutputScriptToAddressesFunc = p.outputScriptToAddresses + return p } // GetChainParams contains network parameters for the main Monacoin network, // and the test Monacoin network func GetChainParams(chain string) *chaincfg.Params { - if MainNetParams.Name == "" { - initParams() + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err == nil { + err = chaincfg.Register(&TestNetParams) + } + if err != nil { + panic(err) + } } switch chain { case "test": @@ -82,17 +82,6 @@ func GetChainParams(chain string) *chaincfg.Params { } } -// GetMonaChainParams contains network parameters for the main Monacoin network, -// and the test Monacoin network -func GetMonaChainParams(chain string) *monacoinCfg.Params { - switch chain { - case "test": - return &MonaTestParams - default: - return &MonaMainParams - } -} - // GetAddrDescFromAddress returns internal address representation (descriptor) of given address func (p *MonacoinParser) GetAddrDescFromAddress(address string) (bchain.AddressDescriptor, error) { return p.addressToOutputScript(address) @@ -123,3 +112,52 @@ func (p *MonacoinParser) addressToOutputScript(address string) ([]byte, error) { return script, nil } } + +// GetAddressesFromAddrDesc returns addresses for given address descriptor with flag if the addresses are searchable +func (p *MonacoinParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) { + return p.OutputScriptToAddressesFunc(addrDesc) +} + +// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses +func (p *MonacoinParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { + switch p.Params.Net { + case MainnetMagic: + sc, addresses, _, err := txscript.ExtractPkScriptAddrs(script, &MonaMainParams) + if err != nil { + return nil, false, err + } + rv := make([]string, len(addresses)) + for i, a := range addresses { + rv[i] = a.EncodeAddress() + } + var s bool + if sc != txscript.NonStandardTy && sc != txscript.NullDataTy { + s = true + } else if len(rv) == 0 { + or := btc.TryParseOPReturn(script) + if or != "" { + rv = []string{or} + } + } + return rv, s, nil + default: + sc, addresses, _, err := txscript.ExtractPkScriptAddrs(script, &MonaTestParams) + if err != nil { + return nil, false, err + } + rv := make([]string, len(addresses)) + for i, a := range addresses { + rv[i] = a.EncodeAddress() + } + var s bool + if sc != txscript.NonStandardTy && sc != txscript.NullDataTy { + s = true + } else if len(rv) == 0 { + or := btc.TryParseOPReturn(script) + if or != "" { + rv = []string{or} + } + } + return rv, s, nil + } +} diff --git a/bchain/coins/monacoin/monacoinparser_test.go b/bchain/coins/monacoin/monacoinparser_test.go index 7c95d9a2..603a082e 100644 --- a/bchain/coins/monacoin/monacoinparser_test.go +++ b/bchain/coins/monacoin/monacoinparser_test.go @@ -7,10 +7,19 @@ import ( "blockbook/bchain/coins/btc" "encoding/hex" "math/big" + "os" "reflect" "testing" + + "github.com/jakm/btcutil/chaincfg" ) +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + func Test_GetAddrDescFromAddress_Testnet(t *testing.T) { type args struct { address string diff --git a/bchain/coins/namecoin/namecoinparser.go b/bchain/coins/namecoin/namecoinparser.go index bca57e55..59e2445a 100644 --- a/bchain/coins/namecoin/namecoinparser.go +++ b/bchain/coins/namecoin/namecoinparser.go @@ -18,16 +18,11 @@ var ( MainNetParams chaincfg.Params ) -func initParams() { +func init() { MainNetParams = chaincfg.MainNetParams MainNetParams.Net = MainnetMagic MainNetParams.PubKeyHashAddrID = []byte{52} MainNetParams.ScriptHashAddrID = []byte{13} - - err := chaincfg.Register(&MainNetParams) - if err != nil { - panic(err) - } } // NamecoinParser handle @@ -43,8 +38,11 @@ func NewNamecoinParser(params *chaincfg.Params, c *btc.Configuration) *NamecoinP // GetChainParams contains network parameters for the main Namecoin network, // and the test Namecoin network func GetChainParams(chain string) *chaincfg.Params { - if MainNetParams.Name == "" { - initParams() + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err != nil { + panic(err) + } } switch chain { default: diff --git a/bchain/coins/namecoin/namecoinparser_test.go b/bchain/coins/namecoin/namecoinparser_test.go index 8eff0e00..dc04a31e 100644 --- a/bchain/coins/namecoin/namecoinparser_test.go +++ b/bchain/coins/namecoin/namecoinparser_test.go @@ -8,11 +8,20 @@ import ( "encoding/hex" "fmt" "io/ioutil" + "os" "path/filepath" "reflect" "testing" + + "github.com/jakm/btcutil/chaincfg" ) +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + func Test_GetAddrDescFromAddress_Mainnet(t *testing.T) { type args struct { address string diff --git a/bchain/coins/vertcoin/vertcoinparser.go b/bchain/coins/vertcoin/vertcoinparser.go index ef7d82fc..ab28083e 100644 --- a/bchain/coins/vertcoin/vertcoinparser.go +++ b/bchain/coins/vertcoin/vertcoinparser.go @@ -18,7 +18,7 @@ var ( TestNetParams chaincfg.Params ) -func initParams() { +func init() { MainNetParams = chaincfg.MainNetParams MainNetParams.Net = MainnetMagic MainNetParams.PubKeyHashAddrID = []byte{71} @@ -30,14 +30,6 @@ func initParams() { TestNetParams.PubKeyHashAddrID = []byte{74} TestNetParams.ScriptHashAddrID = []byte{196} TestNetParams.Bech32HRPSegwit = "tvtc" - - err := chaincfg.Register(&MainNetParams) - if err == nil { - err = chaincfg.Register(&TestNetParams) - } - if err != nil { - panic(err) - } } // VertcoinParser handle @@ -53,8 +45,14 @@ func NewVertcoinParser(params *chaincfg.Params, c *btc.Configuration) *VertcoinP // GetChainParams contains network parameters for the main Vertcoin network, // and the test Vertcoin network func GetChainParams(chain string) *chaincfg.Params { - if MainNetParams.Name == "" { - initParams() + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err == nil { + err = chaincfg.Register(&TestNetParams) + } + if err != nil { + panic(err) + } } switch chain { case "test": diff --git a/bchain/coins/vertcoin/vertcoinparser_test.go b/bchain/coins/vertcoin/vertcoinparser_test.go index 5cdcb5c6..ec86cd67 100644 --- a/bchain/coins/vertcoin/vertcoinparser_test.go +++ b/bchain/coins/vertcoin/vertcoinparser_test.go @@ -7,10 +7,19 @@ import ( "blockbook/bchain/coins/btc" "encoding/hex" "math/big" + "os" "reflect" "testing" + + "github.com/jakm/btcutil/chaincfg" ) +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + func Test_GetAddrDescFromAddress_Mainnet(t *testing.T) { type args struct { address string diff --git a/bchain/coins/zec/zcashparser.go b/bchain/coins/zec/zcashparser.go index ea4917c3..51093c1b 100644 --- a/bchain/coins/zec/zcashparser.go +++ b/bchain/coins/zec/zcashparser.go @@ -17,9 +17,10 @@ const ( var ( MainNetParams chaincfg.Params TestNetParams chaincfg.Params + RegtestParams chaincfg.Params ) -func initParams() { +func init() { MainNetParams = chaincfg.MainNetParams MainNetParams.Net = MainnetMagic @@ -36,13 +37,8 @@ func initParams() { TestNetParams.PubKeyHashAddrID = []byte{0x1D, 0x25} // base58 prefix: tm TestNetParams.ScriptHashAddrID = []byte{0x1C, 0xBA} // base58 prefix: t2 - err := chaincfg.Register(&MainNetParams) - if err == nil { - err = chaincfg.Register(&TestNetParams) - } - if err != nil { - panic(err) - } + RegtestParams = chaincfg.RegressionNetParams + RegtestParams.Net = RegtestMagic } // ZCashParser handle @@ -63,16 +59,24 @@ func NewZCashParser(params *chaincfg.Params, c *btc.Configuration) *ZCashParser // the regression test ZCash network, the test ZCash network and // the simulation test ZCash network, in this order func GetChainParams(chain string) *chaincfg.Params { - if MainNetParams.Name == "" { - initParams() + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err == nil { + err = chaincfg.Register(&TestNetParams) + } + if err == nil { + err = chaincfg.Register(&RegtestParams) + } + if err != nil { + panic(err) + } } var params *chaincfg.Params switch chain { case "test": return &TestNetParams case "regtest": - params = &chaincfg.RegressionNetParams - params.Net = RegtestMagic + return &RegtestParams default: return &MainNetParams } diff --git a/bchain/coins/zec/zcashparser_test.go b/bchain/coins/zec/zcashparser_test.go index ebaf5135..18a6b4a7 100644 --- a/bchain/coins/zec/zcashparser_test.go +++ b/bchain/coins/zec/zcashparser_test.go @@ -8,8 +8,11 @@ import ( "bytes" "encoding/hex" "math/big" + "os" "reflect" "testing" + + "github.com/jakm/btcutil/chaincfg" ) var ( @@ -91,6 +94,12 @@ func init() { } } +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + func TestGetAddrDesc(t *testing.T) { type args struct { tx bchain.Tx diff --git a/build/docker/bin/Makefile b/build/docker/bin/Makefile index f972f896..a9afba42 100644 --- a/build/docker/bin/Makefile +++ b/build/docker/bin/Makefile @@ -1,7 +1,7 @@ SHELL = /bin/bash UPDATE_VENDOR ?= 1 VERSION ?= devel -GITCOMMIT = $(shell cd /src && git describe --tags --always --dirty) +GITCOMMIT = $(shell cd /src && git describe --always --dirty) BUILDTIME = $(shell date --iso-8601=seconds) LDFLAGS := -X blockbook/common.version=$(VERSION) -X blockbook/common.gitcommit=$(GITCOMMIT) -X blockbook/common.buildtime=$(BUILDTIME) BLOCKBOOK_SRC := $(GOPATH)/src/blockbook diff --git a/build/docker/deb/build-deb.sh b/build/docker/deb/build-deb.sh index e4cd23b0..9590c98b 100755 --- a/build/docker/deb/build-deb.sh +++ b/build/docker/deb/build-deb.sh @@ -11,9 +11,10 @@ package=$1 coin=$2 shift 2 -mkdir build +mkdir -p build cp -r /src/build/templates build cp -r /src/configs . +ln -s /src/ /go/src/blockbook go run build/templates/generate.go $coin # backend diff --git a/db/rocksdb.go b/db/rocksdb.go index db46b83c..dd34c6fa 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -42,20 +42,17 @@ type connectBlockStats struct { // RocksDB handle type RocksDB struct { - path string - db *gorocksdb.DB - wo *gorocksdb.WriteOptions - ro *gorocksdb.ReadOptions - cfh []*gorocksdb.ColumnFamilyHandle - chainParser bchain.BlockChainParser - is *common.InternalState - metrics *common.Metrics - cache *gorocksdb.Cache - maxOpenFiles int - cbs connectBlockStats - chanUpdateBalance chan updateBalanceData - chanUpdateBalanceResult chan error - updateBalancesMap map[string]*AddrBalance + path string + db *gorocksdb.DB + wo *gorocksdb.WriteOptions + ro *gorocksdb.ReadOptions + cfh []*gorocksdb.ColumnFamilyHandle + chainParser bchain.BlockChainParser + is *common.InternalState + metrics *common.Metrics + cache *gorocksdb.Cache + maxOpenFiles int + cbs connectBlockStats } const ( @@ -93,20 +90,7 @@ func NewRocksDB(path string, cacheSize, maxOpenFiles int, parser bchain.BlockCha db, cfh, err := openDB(path, c, maxOpenFiles) wo := gorocksdb.NewDefaultWriteOptions() ro := gorocksdb.NewDefaultReadOptions() - rdb := &RocksDB{ - path: path, - db: db, - wo: wo, - ro: ro, - cfh: cfh, - chainParser: parser, - metrics: metrics, - cache: c, - maxOpenFiles: maxOpenFiles, - cbs: connectBlockStats{}, - } - rdb.initUpdateBalancesWorker() - return rdb, nil + return &RocksDB{path, db, wo, ro, cfh, parser, nil, metrics, c, maxOpenFiles, connectBlockStats{}}, nil } func (d *RocksDB) closeDB() error { @@ -290,8 +274,6 @@ func (d *RocksDB) writeBlock(block *bchain.Block, op int) error { txAddressesMap := make(map[string]*TxAddresses) balances := make(map[string]*AddrBalance) if err := d.processAddressesUTXO(block, addresses, txAddressesMap, balances); err != nil { - // reinitialize balanceWorker so that there are no left balances in the queue - d.initUpdateBalancesWorker() return err } if err := d.storeAddresses(wb, block.Height, addresses); err != nil { @@ -380,80 +362,7 @@ func (d *RocksDB) GetAndResetConnectBlockStats() string { return s } -type updateBalanceData struct { - valueSat big.Int - strAddrDesc string - addrDesc bchain.AddressDescriptor - processed, output bool -} - -func (d *RocksDB) initUpdateBalancesWorker() { - if d.chanUpdateBalance != nil { - close(d.chanUpdateBalance) - } - d.chanUpdateBalance = make(chan updateBalanceData, 16) - d.chanUpdateBalanceResult = make(chan error, 16) - go d.updateBalancesWorker() -} - -// updateBalancesWorker is a single worker used to update balances in parallel to processAddressesUTXO -func (d *RocksDB) updateBalancesWorker() { - var err error - for bd := range d.chanUpdateBalance { - ab, e := d.updateBalancesMap[bd.strAddrDesc] - if !e { - ab, err = d.GetAddrDescBalance(bd.addrDesc) - if err != nil { - d.chanUpdateBalanceResult <- err - continue - } - if ab == nil { - ab = &AddrBalance{} - } - d.updateBalancesMap[bd.strAddrDesc] = ab - d.cbs.balancesMiss++ - } else { - d.cbs.balancesHit++ - } - // add number of trx in balance only once, address can be multiple times in tx - if !bd.processed { - ab.Txs++ - } - if bd.output { - ab.BalanceSat.Add(&ab.BalanceSat, &bd.valueSat) - } else { - ab.BalanceSat.Sub(&ab.BalanceSat, &bd.valueSat) - if ab.BalanceSat.Sign() < 0 { - d.resetValueSatToZero(&ab.BalanceSat, bd.addrDesc, "balance") - } - ab.SentSat.Add(&ab.SentSat, &bd.valueSat) - } - d.chanUpdateBalanceResult <- nil - } -} - -func (d *RocksDB) dispatchUpdateBalance(dispatchedBalances int, valueSat *big.Int, strAddrDesc string, addrDesc bchain.AddressDescriptor, processed, output bool) (int, error) { -loop: - for { - select { - // process as many results as possible - case err := <-d.chanUpdateBalanceResult: - if err != nil { - return 0, err - } - dispatchedBalances-- - // send input to be processed - case d.chanUpdateBalance <- updateBalanceData{*valueSat, strAddrDesc, addrDesc, processed, output}: - dispatchedBalances++ - break loop - } - } - return dispatchedBalances, nil -} - func (d *RocksDB) processAddressesUTXO(block *bchain.Block, addresses map[string][]outpoint, txAddressesMap map[string]*TxAddresses, balances map[string]*AddrBalance) error { - d.updateBalancesMap = balances - dispatchedBalances := 0 blockTxIDs := make([][]byte, len(block.Txs)) blockTxAddresses := make([]*TxAddresses, len(block.Txs)) // first process all outputs so that inputs can point to txs in this block @@ -495,10 +404,25 @@ func (d *RocksDB) processAddressesUTXO(block *bchain.Block, addresses map[string btxID: btxID, index: int32(i), }) - dispatchedBalances, err = d.dispatchUpdateBalance(dispatchedBalances, &output.ValueSat, strAddrDesc, addrDesc, processed, true) - if err != nil { - return err + ab, e := balances[strAddrDesc] + if !e { + ab, err = d.GetAddrDescBalance(addrDesc) + if err != nil { + return err + } + if ab == nil { + ab = &AddrBalance{} + } + balances[strAddrDesc] = ab + d.cbs.balancesMiss++ + } else { + d.cbs.balancesHit++ } + // add number of trx in balance only once, address can be multiple times in tx + if !processed { + ab.Txs++ + } + ab.BalanceSat.Add(&ab.BalanceSat, &output.ValueSat) } } // process inputs @@ -564,16 +488,29 @@ func (d *RocksDB) processAddressesUTXO(block *bchain.Block, addresses map[string btxID: spendingTxid, index: ^int32(i), }) - dispatchedBalances, err = d.dispatchUpdateBalance(dispatchedBalances, &ot.ValueSat, strAddrDesc, ot.AddrDesc, processed, false) - if err != nil { - return err + ab, e := balances[strAddrDesc] + if !e { + ab, err = d.GetAddrDescBalance(ot.AddrDesc) + if err != nil { + return err + } + if ab == nil { + ab = &AddrBalance{} + } + balances[strAddrDesc] = ab + d.cbs.balancesMiss++ + } else { + d.cbs.balancesHit++ } - } - } - for i := 0; i < dispatchedBalances; i++ { - err := <-d.chanUpdateBalanceResult - if err != nil { - return err + // add number of trx in balance only once, address can be multiple times in tx + if !processed { + ab.Txs++ + } + ab.BalanceSat.Sub(&ab.BalanceSat, &ot.ValueSat) + if ab.BalanceSat.Sign() < 0 { + d.resetValueSatToZero(&ab.BalanceSat, ot.AddrDesc, "balance") + } + ab.SentSat.Add(&ab.SentSat, &ot.ValueSat) } } return nil diff --git a/db/rocksdb_test.go b/db/rocksdb_test.go index 8e114597..e3aed543 100644 --- a/db/rocksdb_test.go +++ b/db/rocksdb_test.go @@ -18,6 +18,7 @@ import ( "testing" vlq "github.com/bsm/go-vlq" + "github.com/jakm/btcutil/chaincfg" "github.com/juju/errors" ) @@ -25,6 +26,12 @@ import ( // for number n, the packing is: 2*n if n>=0 else 2*(-n)-1 // takes only 1 byte if abs(n)<127 +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + func bitcoinTestnetParser() *btc.BitcoinParser { return btc.NewBitcoinParser( btc.GetChainParams("test"), diff --git a/static/templates/blocks.html b/static/templates/blocks.html index f0728098..b36d8ca8 100644 --- a/static/templates/blocks.html +++ b/static/templates/blocks.html @@ -8,16 +8,18 @@
| Height | +Height | +Hash | Timestamp | -Transactions | -Size | +Transactions | +Size |
|---|---|---|---|---|---|---|---|
| {{$b.Height}} | +{{$b.Hash}} | {{formatUnixTime $b.Time}} | {{$b.Txs}} | {{$b.Size}} | diff --git a/tests/tests.json b/tests/tests.json index b4e38b64..50e88caf 100644 --- a/tests/tests.json +++ b/tests/tests.json @@ -1,11 +1,11 @@ { "bcash": { "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", - "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"] + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"] }, "bcash_testnet": { "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", - "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"] + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"] }, "bitcoin": { "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync",