From ae4cf6b029743cc2b15a405a6bf1e3cc80654c21 Mon Sep 17 00:00:00 2001 From: Sotiris Blad Date: Tue, 30 Apr 2019 17:03:36 +0300 Subject: [PATCH] Add MonetaryUnit (MUE) Support (#166) * MUE * mue parser * mue rpc * mue * mue tests * mue ports * update * update * Create monetaryunitparser_test.go * Update monetaryunitparser_test.go * update * Update monetaryunitparser_test.go * Update monetaryunitparser_test.go * compiling * Update monetaryunitparser_test.go * update hex * test * mue test * Update monetaryunitparser.go * Update monetaryunitparser.go * getblock add * update sum * removed testnet --- bchain/coins/blockchain.go | 2 + .../coins/monetaryunit/monetaryunitparser.go | 182 +++++++++++ .../monetaryunit/monetaryunitparser_test.go | 288 ++++++++++++++++++ bchain/coins/monetaryunit/monetaryunitrpc.go | 97 ++++++ configs/coins/monetaryunit.json | 63 ++++ docs/ports.md | 1 + tests/rpc/testdata/monetaryunit.json | 52 ++++ tests/sync/testdata/monetaryunit.json | 109 +++++++ tests/tests.json | 7 +- 9 files changed, 800 insertions(+), 1 deletion(-) create mode 100644 bchain/coins/monetaryunit/monetaryunitparser.go create mode 100644 bchain/coins/monetaryunit/monetaryunitparser_test.go create mode 100644 bchain/coins/monetaryunit/monetaryunitrpc.go create mode 100644 configs/coins/monetaryunit.json create mode 100644 tests/rpc/testdata/monetaryunit.json create mode 100644 tests/sync/testdata/monetaryunit.json diff --git a/bchain/coins/blockchain.go b/bchain/coins/blockchain.go index 77bf6c1b..957cd9bc 100644 --- a/bchain/coins/blockchain.go +++ b/bchain/coins/blockchain.go @@ -18,6 +18,7 @@ import ( "blockbook/bchain/coins/liquid" "blockbook/bchain/coins/litecoin" "blockbook/bchain/coins/monacoin" + "blockbook/bchain/coins/monetaryunit" "blockbook/bchain/coins/myriad" "blockbook/bchain/coins/namecoin" "blockbook/bchain/coins/nuls" @@ -70,6 +71,7 @@ func init() { BlockChainFactories["Namecoin"] = namecoin.NewNamecoinRPC BlockChainFactories["Monacoin"] = monacoin.NewMonacoinRPC BlockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC + BlockChainFactories["MonetaryUnit"] = monetaryunit.NewMonetaryUnitRPC BlockChainFactories["DigiByte"] = digibyte.NewDigiByteRPC BlockChainFactories["Myriad"] = myriad.NewMyriadRPC BlockChainFactories["Liquid"] = liquid.NewLiquidRPC diff --git a/bchain/coins/monetaryunit/monetaryunitparser.go b/bchain/coins/monetaryunit/monetaryunitparser.go new file mode 100644 index 00000000..91888805 --- /dev/null +++ b/bchain/coins/monetaryunit/monetaryunitparser.go @@ -0,0 +1,182 @@ +package monetaryunit + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "blockbook/bchain/coins/utils" + "bytes" + "io" + + "encoding/hex" + "encoding/json" + + "github.com/juju/errors" + "github.com/martinboehm/btcd/wire" + "github.com/martinboehm/btcutil/chaincfg" +) + +const ( + // Net Magics + MainnetMagic wire.BitcoinNet = 0x91c4fdea + TestnetMagic wire.BitcoinNet = 0x477665bd +) + +var ( + MainNetParams chaincfg.Params + TestNetParams chaincfg.Params +) + +func init() { + // MonetaryUnit mainnet Address encoding magics + MainNetParams = chaincfg.MainNetParams + MainNetParams.Net = MainnetMagic + MainNetParams.PubKeyHashAddrID = []byte{16} // starting with '7' + MainNetParams.ScriptHashAddrID = []byte{76} + MainNetParams.PrivateKeyID = []byte{126} + + // MonetaryUnit testnet Address encoding magics + TestNetParams = chaincfg.TestNet3Params + TestNetParams.Net = TestnetMagic + TestNetParams.PubKeyHashAddrID = []byte{139} // starting with 'x' or 'y' + TestNetParams.ScriptHashAddrID = []byte{19} + TestNetParams.PrivateKeyID = []byte{239} +} + +// MonetaryUnitParser handle +type MonetaryUnitParser struct { + *btc.BitcoinParser + baseparser *bchain.BaseParser + BitcoinOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc +} + +// NewMonetaryUnitParser returns new MonetaryUnitParser instance +func NewMonetaryUnitParser(params *chaincfg.Params, c *btc.Configuration) *MonetaryUnitParser { + p := &MonetaryUnitParser{ + BitcoinParser: btc.NewBitcoinParser(params, c), + baseparser: &bchain.BaseParser{}, + } + p.BitcoinOutputScriptToAddressesFunc = p.OutputScriptToAddressesFunc + p.OutputScriptToAddressesFunc = p.outputScriptToAddresses + return p +} + +// GetChainParams contains network parameters for the main MonetaryUnit network +func GetChainParams(chain string) *chaincfg.Params { + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err == nil { + err = chaincfg.Register(&TestNetParams) + } + if err != nil { + panic(err) + } + } + switch chain { + case "test": + return &TestNetParams + default: + return &MainNetParams + } +} + +// ParseBlock parses raw block to our Block struct +func (p *MonetaryUnitParser) 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, errors.Annotatef(err, "Deserialize") + } + + if h.Version > 3 { + // Skip past AccumulatorCheckpoint which was added in MonetaryUnit block version 4 + r.Seek(32, io.SeekCurrent) + } + + err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w) + if err != nil { + return nil, errors.Annotatef(err, "DecodeTransactions") + } + + 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 +} + +// PackTx packs transaction to byte array using protobuf +func (p *MonetaryUnitParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { + return p.baseparser.PackTx(tx, height, blockTime) +} + +// UnpackTx unpacks transaction from protobuf byte array +func (p *MonetaryUnitParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { + return p.baseparser.UnpackTx(buf) +} + +// ParseTx parses byte array containing transaction and returns Tx struct +func (p *MonetaryUnitParser) ParseTx(b []byte) (*bchain.Tx, error) { + t := wire.MsgTx{} + r := bytes.NewReader(b) + if err := t.Deserialize(r); err != nil { + return nil, err + } + tx := p.TxFromMsgTx(&t, true) + tx.Hex = hex.EncodeToString(b) + return &tx, nil +} + +// ParseTxFromJson parses JSON message containing transaction and returns Tx struct +func (p *MonetaryUnitParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) { + var tx bchain.Tx + err := json.Unmarshal(msg, &tx) + if err != nil { + return nil, err + } + + for i := range tx.Vout { + vout := &tx.Vout[i] + // convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal + vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue) + if err != nil { + return nil, err + } + vout.JsonValue = "" + + if vout.ScriptPubKey.Addresses == nil { + vout.ScriptPubKey.Addresses = []string{} + } + } + + return &tx, nil +} + +// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses +func (p *MonetaryUnitParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { + + rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script) + return rv, s, nil +} + +func (p *MonetaryUnitParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor { + if len(tx.Vin) > input { + scriptHex := tx.Vin[input].ScriptSig.Hex + + if scriptHex != "" { + script, _ := hex.DecodeString(scriptHex) + return script + } + } + + s := make([]byte, 10) + return s +} diff --git a/bchain/coins/monetaryunit/monetaryunitparser_test.go b/bchain/coins/monetaryunit/monetaryunitparser_test.go new file mode 100644 index 00000000..2b902128 --- /dev/null +++ b/bchain/coins/monetaryunit/monetaryunitparser_test.go @@ -0,0 +1,288 @@ +// +build unittest + +package monetaryunit + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "encoding/hex" + "math/big" + "os" + "reflect" + "testing" + + "github.com/martinboehm/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 + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "P2PKH1", + args: args{address: "7cTAePV4rJoSpa6eLhUPSuPpGLdsLiWnXf"}, + want: "76a9146e2b0a8655786c8c5ea7b9ce478f03e00ecb2f5588ac", + wantErr: false, + }, + { + name: "P2PKH2", + args: args{address: "XdmBSxuCLajxZzQQWiY2FEk6XVjiVoqLXW"}, + want: "a91421ba6a62ac1d74d2ba921bbc8c9a3ca6e1420a0087", + wantErr: false, + }, + { + name: "P2SH1", + args: args{address: "bc1q0v3tadxj6pm3ym9j06v9rfyw0jeh5f8squ3nvt"}, + want: "00147b22beb4d2d077126cb27e9851a48e7cb37a24f0", + wantErr: false, + }, + { + name: "P2SH2", + args: args{address: "bc1qumpyvyxz25kfjjrvyxn3zlyc2wfc0m3l3gm5pg99c4mxylemfqhsdf5q0k"}, + want: "0020e6c24610c2552c99486c21a7117c98539387ee3f8a3740a0a5c576627f3b482f", + wantErr: false, + }, + } + parser := NewMonetaryUnitParser(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) + } + }) + } +} + +func Test_GetAddressesFromAddrDesc(t *testing.T) { + type args struct { + script string + } + tests := []struct { + name string + args args + want []string + want2 bool + wantErr bool + }{ + { + name: "P2PKH", + args: args{script: "76a9146e2b0a8655786c8c5ea7b9ce478f03e00ecb2f5588ac"}, + want: []string{"7cTAePV4rJoSpa6eLhUPSuPpGLdsLiWnXf"}, + want2: true, + wantErr: false, + }, + { + name: "P2SH", + args: args{script: "a91421ba6a62ac1d74d2ba921bbc8c9a3ca6e1420a0087"}, + want: []string{"XdmBSxuCLajxZzQQWiY2FEk6XVjiVoqLXW"}, + want2: true, + wantErr: false, + }, + { + name: "P2WPKH", + args: args{script: "00147b22beb4d2d077126cb27e9851a48e7cb37a24f0"}, + want: []string{"bc1q0v3tadxj6pm3ym9j06v9rfyw0jeh5f8squ3nvt"}, + want2: true, + wantErr: false, + }, + { + name: "P2WSH", + args: args{script: "0020e6c24610c2552c99486c21a7117c98539387ee3f8a3740a0a5c576627f3b482f"}, + want: []string{"bc1qumpyvyxz25kfjjrvyxn3zlyc2wfc0m3l3gm5pg99c4mxylemfqhsdf5q0k"}, + want2: true, + wantErr: false, + }, + { + name: "OP_RETURN ascii", + args: args{script: "6a0461686f6a"}, + want: []string{"OP_RETURN (ahoj)"}, + want2: false, + wantErr: false, + }, + { + name: "OP_RETURN hex", + args: args{script: "6a072020f1686f6a20"}, + want: []string{"OP_RETURN 2020f1686f6a20"}, + want2: false, + wantErr: false, + }, + } + + parser := NewMonetaryUnitParser(GetChainParams("main"), &btc.Configuration{}) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b, _ := hex.DecodeString(tt.args.script) + got, got2, err := parser.GetAddressesFromAddrDesc(b) + if (err != nil) != tt.wantErr { + t.Errorf("outputScriptToAddresses() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.want) + } + if !reflect.DeepEqual(got2, tt.want2) { + t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.want2) + } + }) + } +} + +var ( + testTx1 bchain.Tx + + testTxPacked1 = "0a20f05ba72a05c4900ff2a00a0403697750201e41267aeea8a589a7dc7bcc57076e12d30101000000010c396f3768565c707addf85ecf47e04cefb2721d95afd977e13f25904de8336a0100000049483045022100fe1b79f38ca4b9dc2fbc50eac6c9bf050ae5a3ee37da05b950918230eb0a8c7c0220477173b60ec00a8b4b28d5db9fc5d8259eea35f91bbdd60089c5ec1be7b05f3b01ffffffff03000000000000000000dd400def140000002321025d145b77df04c40ceb88ea36828755f8275dc5fecf19d3ecccce2d8198c3407cac00d2496b000000001976a914afe70b2e1bf4199298ed8281767bae22970b415088ac0000000018e6b092e605200028f48d1b32770a0012206a33e84d90253fe177d9af951d72b2ef4ce047cf5ef8dd7a705c5668376f390c18012249483045022100fe1b79f38ca4b9dc2fbc50eac6c9bf050ae5a3ee37da05b950918230eb0a8c7c0220477173b60ec00a8b4b28d5db9fc5d8259eea35f91bbdd60089c5ec1be7b05f3b0128ffffffff0f3a04100022003a520a0514ef0d40dd10011a2321025d145b77df04c40ceb88ea36828755f8275dc5fecf19d3ecccce2d8198c3407cac22223764396a4e79716835694b555a566e516a6d7a6d4541513878444b777a4536536e673a470a046b49d20010021a1976a914afe70b2e1bf4199298ed8281767bae22970b415088ac22223769536a6e57436f41556d4a347656584d6b61457561736e5658537a5a7166504c324001" +) + +func init() { + testTx1 = bchain.Tx{ + Hex: "01000000010c396f3768565c707addf85ecf47e04cefb2721d95afd977e13f25904de8336a0100000049483045022100fe1b79f38ca4b9dc2fbc50eac6c9bf050ae5a3ee37da05b950918230eb0a8c7c0220477173b60ec00a8b4b28d5db9fc5d8259eea35f91bbdd60089c5ec1be7b05f3b01ffffffff03000000000000000000dd400def140000002321025d145b77df04c40ceb88ea36828755f8275dc5fecf19d3ecccce2d8198c3407cac00d2496b000000001976a914afe70b2e1bf4199298ed8281767bae22970b415088ac00000000", + Blocktime: 1556387942, + Txid: "f05ba72a05c4900ff2a00a0403697750201e41267aeea8a589a7dc7bcc57076e", + LockTime: 0, + Time: 1556387942, + Version: 1, + Vin: []bchain.Vin{ + { + ScriptSig: bchain.ScriptSig{ + Hex: "483045022100fe1b79f38ca4b9dc2fbc50eac6c9bf050ae5a3ee37da05b950918230eb0a8c7c0220477173b60ec00a8b4b28d5db9fc5d8259eea35f91bbdd60089c5ec1be7b05f3b01", + }, + Txid: "6a33e84d90253fe177d9af951d72b2ef4ce047cf5ef8dd7a705c5668376f390c", + Vout: 1, + Sequence: 4294967295, + }, + }, + Vout: []bchain.Vout{ + { + ValueSat: *big.NewInt(0), + N: 0, + ScriptPubKey: bchain.ScriptPubKey{ + Hex: "", + Addresses: []string{ + "", + }, + }, + }, + { + ValueSat: *big.NewInt(89909969117), + N: 1, + ScriptPubKey: bchain.ScriptPubKey{ + Hex: "21025d145b77df04c40ceb88ea36828755f8275dc5fecf19d3ecccce2d8198c3407cac", + Addresses: []string{ + "7d9jNyqh5iKUZVnQjmzmEAQ8xDKwzE6Sng", + }, + }, + }, + { + ValueSat: *big.NewInt(1800000000), + N: 2, + ScriptPubKey: bchain.ScriptPubKey{ + Hex: "76a914afe70b2e1bf4199298ed8281767bae22970b415088ac", + Addresses: []string{ + "7iSjnWCoAUmJ4vVXMkaEuasnVXSzZqfPL2", + }, + }, + }, + }, + } +} + +func Test_PackTx(t *testing.T) { + type args struct { + tx bchain.Tx + height uint32 + blockTime int64 + parser *MonetaryUnitParser + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "monetaryunit-1", + args: args{ + tx: testTx1, + height: 444148, + blockTime: 1556387942, + parser: NewMonetaryUnitParser(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 *MonetaryUnitParser + } + tests := []struct { + name string + args args + want *bchain.Tx + want1 uint32 + wantErr bool + }{ + { + name: "monetaryunit-1", + args: args{ + packedTx: testTxPacked1, + parser: NewMonetaryUnitParser(GetChainParams("main"), &btc.Configuration{}), + }, + want: &testTx1, + want1: 444148, + 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/monetaryunit/monetaryunitrpc.go b/bchain/coins/monetaryunit/monetaryunitrpc.go new file mode 100644 index 00000000..11143b3b --- /dev/null +++ b/bchain/coins/monetaryunit/monetaryunitrpc.go @@ -0,0 +1,97 @@ +package monetaryunit + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "encoding/json" + + "github.com/golang/glog" +) + +// MonetaryUnitRPC is an interface to JSON-RPC bitcoind service. +type MonetaryUnitRPC struct { + *btc.BitcoinRPC +} + +// NewMonetaryUnitRPC returns new MonetaryUnitRPC instance. +func NewMonetaryUnitRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) { + b, err := btc.NewBitcoinRPC(config, pushHandler) + if err != nil { + return nil, err + } + + s := &MonetaryUnitRPC{ + b.(*btc.BitcoinRPC), + } + s.RPCMarshaler = btc.JSONMarshalerV1{} + s.ChainConfig.SupportsEstimateFee = true + s.ChainConfig.SupportsEstimateSmartFee = false + + return s, nil +} + +// Initialize initializes MonetaryUnitRPC instance. +func (b *MonetaryUnitRPC) Initialize() error { + ci, err := b.GetChainInfo() + if err != nil { + return err + } + chainName := ci.Chain + + glog.Info("Chain name ", chainName) + params := GetChainParams(chainName) + + // always create parser + b.Parser = NewMonetaryUnitParser(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 +} + +// Get Block +func (b *MonetaryUnitRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) { + + var err error + if hash == "" && height > 0 { + hash, err = b.GetBlockHash(height) + if err != nil { + return nil, err + } + } + + glog.V(1).Info("rpc: getblock (verbosity=1) ", hash) + + res := btc.ResGetBlockThin{} + req := btc.CmdGetBlock{Method: "getblock"} + req.Params.BlockHash = hash + req.Params.Verbosity = 1 + err = b.Call(&req, &res) + + txs := make([]bchain.Tx, 0, len(res.Result.Txids)) + for _, txid := range res.Result.Txids { + tx, err := b.GetTransaction(txid) + if err != nil { + if err == bchain.ErrTxNotFound { + glog.Errorf("rpc: getblock: skipping transanction in block %s due error: %s", hash, err) + continue + } + return nil, err + } + txs = append(txs, *tx) + } + block := &bchain.Block{ + BlockHeader: res.Result.BlockHeader, + Txs: txs, + } + return block, nil +} diff --git a/configs/coins/monetaryunit.json b/configs/coins/monetaryunit.json new file mode 100644 index 00000000..1e5c6e8c --- /dev/null +++ b/configs/coins/monetaryunit.json @@ -0,0 +1,63 @@ +{ + "coin": { + "name": "MonetaryUnit", + "shortcut": "MUE", + "label": "MonetaryUnit", + "alias": "monetaryunit" + }, + "ports": { + "backend_rpc": 8057, + "backend_message_queue": 38357, + "blockbook_internal": 9057, + "blockbook_public": 9157 + }, + "ipc": { + "rpc_url_template": "http://127.0.0.1:{{.Ports.BackendRPC}}", + "rpc_user": "rpc", + "rpc_pass": "monetaryunitrpc", + "rpc_timeout": 25, + "message_queue_binding_template": "tcp://127.0.0.1:{{.Ports.BackendMessageQueue}}" + }, + "backend": { + "package_name": "backend-monetaryunit", + "package_revision": "satoshilabs-1", + "system_user": "monetaryunit", + "version": "2.1.4", + "binary_url": "https://github.com/muecoin/MUE/releases/download/v2.1.4/mon-2.1.4-x86_64-linux-gnu.tar.gz", + "verification_type": "sha256", + "verification_source": "1c6885f3e5bb1efcc8c84e7910ec57bf76573983f2026ea7c5a7a919b7abcc11", + "extract_command": "tar -C backend --strip 1 -xf", + "exclude_files": ["bin/monetaryunit-qt"], + "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/monetaryunitd -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": false, + "mainnet": true, + "server_config_file": "bitcoin_like.conf", + "client_config_file": "bitcoin_like_client.conf", + "additional_params": { + "whitelist": "127.0.0.1" + } + }, + "blockbook": { + "package_name": "blockbook-monetaryunit", + "system_user": "blockbook-monetaryunit", + "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": "sotblad", + "package_maintainer_email": "swthrhs@protonmail.com" + } +} diff --git a/docs/ports.md b/docs/ports.md index 7c671005..e1dfc174 100644 --- a/docs/ports.md +++ b/docs/ports.md @@ -28,6 +28,7 @@ | NULS | 9053 | 9153 | 8053 | 38353 | | Viacoin | 9055 | 9155 | 8055 | 38355 | | VIPSTARCOIN | 9056 | 9156 | 8056 | 38356 | +| MonetaryUnit | 9057 | 9157 | 8057 | 38357 | | Flo | 9066 | 9166 | 8066 | 38366 | | Polis | 9067 | 9167 | 8067 | 38367 | | Qtum | 9088 | 9188 | 8088 | 38388 | diff --git a/tests/rpc/testdata/monetaryunit.json b/tests/rpc/testdata/monetaryunit.json new file mode 100644 index 00000000..7dcaa0c8 --- /dev/null +++ b/tests/rpc/testdata/monetaryunit.json @@ -0,0 +1,52 @@ +{ + "blockHeight": 447973, + "blockHash": "c81fe0f3524938c618156449d27ede51c2c76b73e00e83cdb9b599181ca505d5", + "blockTime": 1556541002, + "blockTxs": [ + "062f1f851b5d350f860a2c96c98b6dac8030f84bb02df42b5608619abf6049c8", + "72502137b0924c69400eec74deacc57e9290f32a6ba2f5559f17256c9c06a347" + ], + "txDetails": { + "72502137b0924c69400eec74deacc57e9290f32a6ba2f5559f17256c9c06a347": { + "hex": "0100000001ac2e21335c11482009e10d78ddf0378e2e778f09ec01077d3ac7747ac4f3eae5010000004847304402201de5db6155e047897ea2fed2a8cbc1d717fb8c5b1a18964cd4942c800db1a218022035a6c8aed82c582db22f4835dbd86a283c7ed3b84eaf1f68932b910dfd08d1be01ffffffff030000000000000000008e36f7c90d00000023210219e5714cbba5933a9c09bc93330efece366f61910ee1cc38b245e420063ca3f2ac00d2496b000000001976a914a1f4fccad310761f842f3cdcc41b5ca3220fd30488ac00000000", + "txid": "72502137b0924c69400eec74deacc57e9290f32a6ba2f5559f17256c9c06a347", + "blocktime": 1556541002, + "time": 1556541002, + "locktime": 0, + "version": 1, + "vin": [ + { + "txid": "e5eaf3c47a74c73a7d0701ec098f772e8e37f0dd780de1092048115c33212eac", + "vout": 1, + "scriptSig": { + "hex": "47304402201de5db6155e047897ea2fed2a8cbc1d717fb8c5b1a18964cd4942c800db1a218022035a6c8aed82c582db22f4835dbd86a283c7ed3b84eaf1f68932b910dfd08d1be01" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.00000000, + "n": 0, + "scriptPubKey": { + "hex": "" + } + }, + { + "value": 592.22996622, + "n": 1, + "scriptPubKey": { + "hex": "210219e5714cbba5933a9c09bc93330efece366f61910ee1cc38b245e420063ca3f2ac" + } + }, + { + "value": 18, + "n": 2, + "scriptPubKey": { + "hex": "76a914a1f4fccad310761f842f3cdcc41b5ca3220fd30488ac" + } + } + ] + } + } +} diff --git a/tests/sync/testdata/monetaryunit.json b/tests/sync/testdata/monetaryunit.json new file mode 100644 index 00000000..15b48e64 --- /dev/null +++ b/tests/sync/testdata/monetaryunit.json @@ -0,0 +1,109 @@ +{ + "connectBlocks": { + "syncRanges": [{ "lower": 447973, "upper": 447973 }], + "blocks": { + "447973": { + "height": 447973, + "hash": "c81fe0f3524938c618156449d27ede51c2c76b73e00e83cdb9b599181ca505d5", + "noTxs": 2, + "txDetails": [ + { + "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0603e5d5060101ffffffff0100000000000000000000000000", + "txid": "062f1f851b5d350f860a2c96c98b6dac8030f84bb02df42b5608619abf6049c8", + "version": 1, + "locktime": 0, + "vin": [ + { + "coinbase": "03e5d5060101", + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0, + "n": 0, + "scriptPubKey": { + "asm": "", + "hex": "", + "type": "nonstandard" + } + } + ], + "blockhash": "c81fe0f3524938c618156449d27ede51c2c76b73e00e83cdb9b599181ca505d5", + "confirmations": 61, + "time": 1556541002, + "blocktime": 1556541002 + }, + { + "txid": "72502137b0924c69400eec74deacc57e9290f32a6ba2f5559f17256c9c06a347", + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": "e5eaf3c47a74c73a7d0701ec098f772e8e37f0dd780de1092048115c33212eac", + "vout": 1, + "scriptSig": { + "asm": "304402201de5db6155e047897ea2fed2a8cbc1d717fb8c5b1a18964cd4942c800db1a218022035a6c8aed82c582db22f4835dbd86a283c7ed3b84eaf1f68932b910dfd08d1be01", + "hex": "47304402201de5db6155e047897ea2fed2a8cbc1d717fb8c5b1a18964cd4942c800db1a218022035a6c8aed82c582db22f4835dbd86a283c7ed3b84eaf1f68932b910dfd08d1be01" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0, + "n": 0, + "scriptPubKey": { + "asm": "", + "hex": "", + "type": "nonstandard" + } + }, + { + "value": 592.22996622, + "n": 1, + "scriptPubKey": { + "asm": "0219e5714cbba5933a9c09bc93330efece366f61910ee1cc38b245e420063ca3f2 OP_CHECKSIG", + "hex": "210219e5714cbba5933a9c09bc93330efece366f61910ee1cc38b245e420063ca3f2ac", + "reqSigs": 1, + "type": "pubkey", + "addresses": ["7onpME5risJYB6JrcfHGUPdnbsYUL4yhkf"] + } + }, + { + "value": 18, + "n": 2, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 a1f4fccad310761f842f3cdcc41b5ca3220fd304 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914a1f4fccad310761f842f3cdcc41b5ca3220fd30488ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": ["7hB12ehKqJZZHbyin154CsXehPvdcQWgLX"] + } + } + ], + "blockhash": "c81fe0f3524938c618156449d27ede51c2c76b73e00e83cdb9b599181ca505d5", + "confirmations": 65, + "time": 1556541002, + "blocktime": 1556541002 + } + ] + } + } + }, + "handleFork": { + "syncRanges": [{ "lower": 447973, "upper": 447973 }], + "fakeBlocks": { + "447973": { + "height": 447973, + "hash": "4bdd44aa35b2f0db83d2e244561e5bf059b89f3b418c31935d898f597418bf78" + } + }, + "realBlocks": { + "447973": { + "height": 447973, + "hash": "c81fe0f3524938c618156449d27ede51c2c76b73e00e83cdb9b599181ca505d5" + } + } + } +} diff --git a/tests/tests.json b/tests/tests.json index 756ad06c..52760916 100644 --- a/tests/tests.json +++ b/tests/tests.json @@ -145,5 +145,10 @@ "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] - } + }, + "monetaryunit": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + } }