From 2304c777326fa997eeb20fa00ed19a09847ec908 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Tue, 2 Oct 2018 12:09:04 +0200 Subject: [PATCH 1/3] Add build time to blockbook_app_info prometheus metrics --- blockbook.go | 1 + common/metrics.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/blockbook.go b/blockbook.go index 41fc8a73..7f501f6b 100644 --- a/blockbook.go +++ b/blockbook.go @@ -362,6 +362,7 @@ func blockbookAppInfoMetric(db *db.RocksDB, chain bchain.BlockChain, txCache *db metrics.BlockbookAppInfo.With(common.Labels{ "blockbook_version": si.Blockbook.Version, "blockbook_commit": si.Blockbook.GitCommit, + "blockbook_buildtime": si.Blockbook.BuildTime, "backend_version": si.Backend.Version, "backend_subversion": si.Backend.Subversion, "backend_protocol_version": si.Backend.ProtocolVersion}).Set(float64(0)) diff --git a/common/metrics.go b/common/metrics.go index 9451180b..6e338195 100644 --- a/common/metrics.go +++ b/common/metrics.go @@ -146,7 +146,7 @@ func GetMetrics(coin string) (*Metrics, error) { Help: "Information about blockbook and backend application versions", ConstLabels: Labels{"coin": coin}, }, - []string{"blockbook_version", "blockbook_commit", "backend_version", "backend_subversion", "backend_protocol_version"}, + []string{"blockbook_version", "blockbook_commit", "blockbook_buildtime", "backend_version", "backend_subversion", "backend_protocol_version"}, ) v := reflect.ValueOf(metrics) From 8c41cf2356c766b61f9cc7ebdf4678548e2382da Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Tue, 2 Oct 2018 12:36:43 +0200 Subject: [PATCH 2/3] Switch namecoin to EstimateSmartFee rpc call --- bchain/coins/namecoin/namecoinrpc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bchain/coins/namecoin/namecoinrpc.go b/bchain/coins/namecoin/namecoinrpc.go index 6ab0b0aa..89dc245c 100644 --- a/bchain/coins/namecoin/namecoinrpc.go +++ b/bchain/coins/namecoin/namecoinrpc.go @@ -24,7 +24,7 @@ func NewNamecoinRPC(config json.RawMessage, pushHandler func(bchain.Notification b.(*btc.BitcoinRPC), } s.RPCMarshaler = btc.JSONMarshalerV1{} - s.ChainConfig.SupportsEstimateSmartFee = false + s.ChainConfig.SupportsEstimateFee = false return s, nil } From ecf6ca3081b4daace5a3b9a9e61187a21aab3dde Mon Sep 17 00:00:00 2001 From: wlc- Date: Tue, 2 Oct 2018 17:09:56 +0200 Subject: [PATCH 3/3] Add Myriad (#68) * Myriad * [Myriad] Use Internal Explorer * [Myriad] Add size and time to ParseBlock --- bchain/coins/blockchain.go | 2 + bchain/coins/myriad/myriadparser.go | 93 +++++++++++ bchain/coins/myriad/myriadparser_test.go | 187 +++++++++++++++++++++++ bchain/coins/myriad/myriadrpc.go | 71 +++++++++ configs/coins/myriad.json | 64 ++++++++ docs/ports.md | 1 + tests/rpc/testdata/myriad.json | 46 ++++++ tests/tests.json | 4 + 8 files changed, 468 insertions(+) create mode 100644 bchain/coins/myriad/myriadparser.go create mode 100644 bchain/coins/myriad/myriadparser_test.go create mode 100644 bchain/coins/myriad/myriadrpc.go create mode 100644 configs/coins/myriad.json create mode 100644 tests/rpc/testdata/myriad.json diff --git a/bchain/coins/blockchain.go b/bchain/coins/blockchain.go index 35315d80..98bb4efd 100644 --- a/bchain/coins/blockchain.go +++ b/bchain/coins/blockchain.go @@ -10,6 +10,7 @@ import ( "blockbook/bchain/coins/eth" "blockbook/bchain/coins/litecoin" "blockbook/bchain/coins/monacoin" + "blockbook/bchain/coins/myriad" "blockbook/bchain/coins/namecoin" "blockbook/bchain/coins/vertcoin" "blockbook/bchain/coins/zec" @@ -50,6 +51,7 @@ func init() { BlockChainFactories["Namecoin"] = namecoin.NewNamecoinRPC BlockChainFactories["Monacoin"] = monacoin.NewMonacoinRPC BlockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC + BlockChainFactories["Myriad"] = myriad.NewMyriadRPC } // GetCoinNameFromConfig gets coin name and coin shortcut from config file diff --git a/bchain/coins/myriad/myriadparser.go b/bchain/coins/myriad/myriadparser.go new file mode 100644 index 00000000..309f7e8b --- /dev/null +++ b/bchain/coins/myriad/myriadparser.go @@ -0,0 +1,93 @@ +package myriad + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "blockbook/bchain/coins/utils" + "bytes" + + "github.com/jakm/btcutil/chaincfg" + "github.com/btcsuite/btcd/wire" +) + +const ( + MainnetMagic wire.BitcoinNet = 0xee7645af +) + +var ( + MainNetParams chaincfg.Params +) + +func initParams() { + MainNetParams = chaincfg.MainNetParams + MainNetParams.Net = MainnetMagic + + MainNetParams.Bech32HRPSegwit = "my" + + MainNetParams.PubKeyHashAddrID = []byte{50} // 0x32 - starts with M + MainNetParams.ScriptHashAddrID = []byte{9} // 0x09 - starts with 4 + MainNetParams.PrivateKeyID = []byte{178} // 0xB2 + + MainNetParams.HDCoinType = 90 + + err := chaincfg.Register(&MainNetParams) + if err != nil { + panic(err) + } +} + +// MyriadParser handle +type MyriadParser struct { + *btc.BitcoinParser +} + +// NewMyriadParser returns new MyriadParser instance +func NewMyriadParser(params *chaincfg.Params, c *btc.Configuration) *MyriadParser { + return &MyriadParser{BitcoinParser: btc.NewBitcoinParser(params, c)} +} + +// GetChainParams contains network parameters for the main Myriad network +func GetChainParams(chain string) *chaincfg.Params { + if MainNetParams.Name == "" { + initParams() + } + switch chain { + default: + return &MainNetParams + } +} + +// ParseBlock parses raw block to our Block struct +// it has special handling for Auxpow blocks that cannot be parsed by standard btc wire parser +func (p *MyriadParser) ParseBlock(b []byte) (*bchain.Block, error) { + r := bytes.NewReader(b) + w := wire.MsgBlock{} + h := wire.BlockHeader{} + err := h.Deserialize(r) + if err != nil { + return nil, err + } + if (h.Version & utils.VersionAuxpow) != 0 { + if err = utils.SkipAuxpow(r); err != nil { + return nil, err + } + } + + err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w) + if err != nil { + return nil, err + } + + txs := make([]bchain.Tx, len(w.Transactions)) + for ti, t := range w.Transactions { + txs[ti] = p.TxFromMsgTx(t, false) + } + + return &bchain.Block{ + BlockHeader: bchain.BlockHeader{ + Size: len(b), + Time: h.Timestamp.Unix(), + }, + Txs: txs, + }, nil +} diff --git a/bchain/coins/myriad/myriadparser_test.go b/bchain/coins/myriad/myriadparser_test.go new file mode 100644 index 00000000..164e9ab9 --- /dev/null +++ b/bchain/coins/myriad/myriadparser_test.go @@ -0,0 +1,187 @@ +// +build unittest + +package myriad + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "encoding/hex" + "math/big" + "reflect" + "testing" +) + +func Test_GetAddrDescFromAddress_Mainnet(t *testing.T) { + type args struct { + address string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "P2PKH1", + args: args{address: "MUs3PnZLdBQyct2emEc7QJvVnjeQj52kug"}, + want: "76a914e5f419d3b464c67152fb9d3ecc36932d5280673f88ac", + wantErr: false, + }, + { + name: "P2SH1", + args: args{address: "4ijSZESajWvhhJAz1APdzGivwc31WCjxHD"}, + want: "a9143e69d8c4772eb34d77c96aae58c041e887b404f387", + wantErr: false, + }, + { + name: "witness_v0_keyhash", + args: args{address: "my1qr9y3pd7wy7jjpqf87qsmp08ecppc0p2jxhfcfc"}, + want: "0014194910b7ce27a5208127f021b0bcf9c043878552", + wantErr: false, + }, + } + parser := NewMyriadParser(GetChainParams("main"), &btc.Configuration{}) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parser.GetAddrDescFromAddress(tt.args.address) + if (err != nil) != tt.wantErr { + t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr) + return + } + h := hex.EncodeToString(got) + if !reflect.DeepEqual(h, tt.want) { + t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want) + } + }) + } +} + + +var ( + testTx1 bchain.Tx + testTxPacked1 = "00004e208ab194a1180100000001163465df9bb21d89e90056f11887a398d5a313aef71e3974306459661a91588c000000006b4830450220129c9e9a27406796f3f7d7edcc446037b38ddb3ef94745cec8e7cde618a811140221008eb3b893cdd3725e99b74c020867821e1f74199065260586f5ef3c22b133dd2a012103e2e23d38dc8fa493cde4077f650ab9f22eacafd14a10b123994f38c9f35dfee9ffffffff025e90ec28050000001976a9141cba92fe1510b8c73550fd4d3e0b44acdffcd12d88ac79c268ba0a0000001976a9142f86cdfa98cac89143cf9e3d309cc072caccdf6f88ac00000000" +) + +func init() { + testTx1 = bchain.Tx{ + Hex: "0100000001163465df9bb21d89e90056f11887a398d5a313aef71e3974306459661a91588c000000006b4830450220129c9e9a27406796f3f7d7edcc446037b38ddb3ef94745cec8e7cde618a811140221008eb3b893cdd3725e99b74c020867821e1f74199065260586f5ef3c22b133dd2a012103e2e23d38dc8fa493cde4077f650ab9f22eacafd14a10b123994f38c9f35dfee9ffffffff025e90ec28050000001976a9141cba92fe1510b8c73550fd4d3e0b44acdffcd12d88ac79c268ba0a0000001976a9142f86cdfa98cac89143cf9e3d309cc072caccdf6f88ac00000000", + Blocktime: 1393723468, + Txid: "b01e2eb866ed101ed117b4ad18b753929e85c42e3d8add76bdd16e5c00519dcc", + LockTime: 0, + Version: 1, + Vin: []bchain.Vin{ + { + ScriptSig: bchain.ScriptSig{ + Hex: "4830450220129c9e9a27406796f3f7d7edcc446037b38ddb3ef94745cec8e7cde618a811140221008eb3b893cdd3725e99b74c020867821e1f74199065260586f5ef3c22b133dd2a012103e2e23d38dc8fa493cde4077f650ab9f22eacafd14a10b123994f38c9f35dfee9", + }, + Txid: "8c58911a6659643074391ef7ae13a3d598a38718f15600e9891db29bdf653416", + Vout: 0, + Sequence: 4294967295, + }, + }, + Vout: []bchain.Vout{ + { + ValueSat: *big.NewInt(22161428574), + N: 0, + ScriptPubKey: bchain.ScriptPubKey{ + Hex: "76a9141cba92fe1510b8c73550fd4d3e0b44acdffcd12d88ac", + Addresses: []string{ + "MAX4fCkTJwaRzbA3xzJp9DjrMwnnK32T6Z", + }, + }, + }, + { + ValueSat: *big.NewInt(46077100665), + N: 1, + ScriptPubKey: bchain.ScriptPubKey{ + Hex: "76a9142f86cdfa98cac89143cf9e3d309cc072caccdf6f88ac", + Addresses: []string{ + "MCETUqM7MH6NietcsPY3w2sVUKz255m1yY", + }, + }, + }, + }, + } +} + +func Test_PackTx(t *testing.T) { + type args struct { + tx bchain.Tx + height uint32 + blockTime int64 + parser *MyriadParser + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "myriad-1", + args: args{ + tx: testTx1, + height: 20000, + blockTime: 1393723468, + parser: NewMyriadParser(GetChainParams("main"), &btc.Configuration{}), + }, + want: testTxPacked1, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.args.parser.PackTx(&tt.args.tx, tt.args.height, tt.args.blockTime) + if (err != nil) != tt.wantErr { + t.Errorf("packTx() error = %v, wantErr %v", err, tt.wantErr) + return + } + h := hex.EncodeToString(got) + if !reflect.DeepEqual(h, tt.want) { + t.Errorf("packTx() = %v, want %v", h, tt.want) + } + }) + } +} + +func Test_UnpackTx(t *testing.T) { + type args struct { + packedTx string + parser *MyriadParser + } + tests := []struct { + name string + args args + want *bchain.Tx + want1 uint32 + wantErr bool + }{ + { + name: "myriad-1", + args: args{ + packedTx: testTxPacked1, + parser: NewMyriadParser(GetChainParams("main"), &btc.Configuration{}), + }, + want: &testTx1, + want1: 20000, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b, _ := hex.DecodeString(tt.args.packedTx) + got, got1, err := tt.args.parser.UnpackTx(b) + if (err != nil) != tt.wantErr { + t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("unpackTx() got = %v, want %v", got, tt.want) + } + if got1 != tt.want1 { + t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} diff --git a/bchain/coins/myriad/myriadrpc.go b/bchain/coins/myriad/myriadrpc.go new file mode 100644 index 00000000..bc5f412e --- /dev/null +++ b/bchain/coins/myriad/myriadrpc.go @@ -0,0 +1,71 @@ +package myriad + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "encoding/json" + + "github.com/golang/glog" +) + +// MyriadRPC is an interface to JSON-RPC bitcoind service. +type MyriadRPC struct { + *btc.BitcoinRPC +} + +// NewMyriadRPC returns new MyriadRPC instance. +func NewMyriadRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) { + b, err := btc.NewBitcoinRPC(config, pushHandler) + if err != nil { + return nil, err + } + + s := &MyriadRPC{ + b.(*btc.BitcoinRPC), + } + s.RPCMarshaler = btc.JSONMarshalerV2{} + + return s, nil +} + +// Initialize initializes MyriadRPC instance. +func (b *MyriadRPC) Initialize() error { + chainName, err := b.GetChainInfoAndInitializeMempool(b) + if err != nil { + return err + } + + glog.Info("Chain name ", chainName) + params := GetChainParams(chainName) + + // always create parser + b.Parser = NewMyriadParser(params, b.ChainConfig) + + // parameters for getInfo request + if params.Net == MainnetMagic { + b.Testnet = false + b.Network = "livenet" + } else { + b.Testnet = true + b.Network = "testnet" + } + + glog.Info("rpc: block chain ", params.Name) + + return nil +} + +// GetBlock returns block with given hash. +func (b *MyriadRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) { + var err error + if hash == "" { + hash, err = b.GetBlockHash(height) + if err != nil { + return nil, err + } + } + if !b.ParseBlocks { + return b.GetBlockFull(hash) + } + return b.GetBlockWithoutHeader(hash, height) +} diff --git a/configs/coins/myriad.json b/configs/coins/myriad.json new file mode 100644 index 00000000..a125b4f9 --- /dev/null +++ b/configs/coins/myriad.json @@ -0,0 +1,64 @@ +{ + "coin": { + "name": "Myriad", + "shortcut": "XMY", + "label": "Myriad", + "alias": "myriad" + }, + "ports": { + "backend_rpc": 8043, + "backend_message_queue": 38343, + "blockbook_internal": 9043, + "blockbook_public": 9143 + }, + "ipc": { + "rpc_url_template": "http://127.0.0.1:{{.Ports.BackendRPC}}", + "rpc_user": "rpc", + "rpc_pass": "rpc", + "rpc_timeout": 25, + "message_queue_binding_template": "tcp://127.0.0.1:{{.Ports.BackendMessageQueue}}" + }, + "backend": { + "package_name": "backend-myriad", + "package_revision": "satoshilabs-1", + "system_user": "myriad", + "version": "0.16.3.0", + "binary_url": "https://github.com/myriadteam/myriadcoin/releases/download/v0.16.3.0-beta0/myriadcoin-0.16.3.0-beta0-x86_64-linux-gnu.tar.gz", + "verification_type": "sha256", + "verification_source": "36b076eebb5951d7b2bc3c2d4654c76024fbabb3ea5a82c987d05c462a09324c", + "extract_command": "tar -C backend --strip 1 -xf", + "exclude_files": [ + "bin/myriadcoin-qt" + ], + "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/myriadcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/*.log", + "postinst_script_template": "", + "service_type": "forking", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "config_file": "bitcoin.conf", + "additional_params": { + "whitelist": "127.0.0.1" + } + }, + "blockbook": { + "package_name": "blockbook-myriad", + "system_user": "blockbook-myriad", + "internal_binding_template": ":{{.Ports.BlockbookInternal}}", + "public_binding_template": ":{{.Ports.BlockbookPublic}}", + "explorer_url": "", + "additional_params": "", + "block_chain": { + "parse": true, + "mempool_workers": 8, + "mempool_sub_workers": 2, + "block_addresses_to_keep": 300, + "additional_params": {} + } + }, + "meta": { + "package_maintainer": "wlc-", + "package_maintainer_email": "wwwwllllcccc@gmail.com" + } +} diff --git a/docs/ports.md b/docs/ports.md index e400f01d..d12ead0e 100644 --- a/docs/ports.md +++ b/docs/ports.md @@ -14,6 +14,7 @@ | Namecoin | 9039 | 9139 | 8039 | 38339 | | Vertcoin | 9040 | 9140 | 8040 | 38340 | | Monacoin | 9041 | 9141 | 8041 | 38341 | +| Myriad | 9043 | 9143 | 8043 | 38343 | | Testnet | 19030 | 19130 | 18030 | 48330 | | Bcash Testnet | 19031 | 19131 | 18031 | 48331 | | Zcash Testnet | 19032 | 19132 | 18032 | 48332 | diff --git a/tests/rpc/testdata/myriad.json b/tests/rpc/testdata/myriad.json new file mode 100644 index 00000000..3d79b159 --- /dev/null +++ b/tests/rpc/testdata/myriad.json @@ -0,0 +1,46 @@ +{ + "blockHeight": 20000, + "blockHash": "a5eac2e226d40d758059c3b5041372c82f49e5df72047424187be72bab410885", + "blockTime": 1393723468, + "blockTxs": [ + "b5860208ff392f5c750fd4e0d5c8d647f9fc9e1d30a1b5401d3717a9fc604c16", + "b01e2eb866ed101ed117b4ad18b753929e85c42e3d8add76bdd16e5c00519dcc", + "834e1498be0c5b00dfa5db855f18c69aff19ff9f823b05922077c0875057bce0" + ], + "txDetails": { + "b01e2eb866ed101ed117b4ad18b753929e85c42e3d8add76bdd16e5c00519dcc": { + "hex": "0100000001163465df9bb21d89e90056f11887a398d5a313aef71e3974306459661a91588c000000006b4830450220129c9e9a27406796f3f7d7edcc446037b38ddb3ef94745cec8e7cde618a811140221008eb3b893cdd3725e99b74c020867821e1f74199065260586f5ef3c22b133dd2a012103e2e23d38dc8fa493cde4077f650ab9f22eacafd14a10b123994f38c9f35dfee9ffffffff025e90ec28050000001976a9141cba92fe1510b8c73550fd4d3e0b44acdffcd12d88ac79c268ba0a0000001976a9142f86cdfa98cac89143cf9e3d309cc072caccdf6f88ac00000000", + "txid": "b01e2eb866ed101ed117b4ad18b753929e85c42e3d8add76bdd16e5c00519dcc", + "blocktime": 1393723468, + "time": 1393723468, + "locktime": 0, + "version": 1, + "vin": [ + { + "txid": "8c58911a6659643074391ef7ae13a3d598a38718f15600e9891db29bdf653416", + "vout": 0, + "sequence": 4294967295, + "scriptSig": { + "hex": "4830450220129c9e9a27406796f3f7d7edcc446037b38ddb3ef94745cec8e7cde618a811140221008eb3b893cdd3725e99b74c020867821e1f74199065260586f5ef3c22b133dd2a012103e2e23d38dc8fa493cde4077f650ab9f22eacafd14a10b123994f38c9f35dfee9" + } + } + ], + "vout": [ + { + "value": 221.61428574, + "n": 0, + "scriptPubKey": { + "hex": "76a9141cba92fe1510b8c73550fd4d3e0b44acdffcd12d88ac" + } + }, + { + "value": 460.77100665, + "n": 1, + "scriptPubKey": { + "hex": "76a9142f86cdfa98cac89143cf9e3d309cc072caccdf6f88ac" + } + } + ] + } + } +} diff --git a/tests/tests.json b/tests/tests.json index 9f67d440..e323ef71 100644 --- a/tests/tests.json +++ b/tests/tests.json @@ -38,6 +38,10 @@ "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee", "EstimateFee"] }, + "myriad": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"] + }, "namecoin": { "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "MempoolSync", "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]