diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 3eea619e9d..0000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,193 +0,0 @@ -stages: - - build - - test - - backend-deploy-and-test - -build: - stage: build - only: - - master - tags: - - blockbook - script: make build - -unit-test: - stage: test - only: - - master - tags: - - blockbook - script: make test - -integration-test: - stage: test - only: - - schedules - tags: - - blockbook - script: make test-integration ARGS="-run='TestIntegration/(bcash|bgold|bitcoin|dash|dogecoin|litecoin|vertcoin|zcash|syscoin)=main/'" - -backend-deploy-and-test-bcash: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/bcash.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh bcash - -backend-deploy-and-test-bgold: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/bgold.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh bgold - -backend-deploy-and-test-bitcoin: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/bitcoin.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh bitcoin - -backend-deploy-and-test-dash: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/dash.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh dash - -backend-deploy-and-test-digibyte: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/digibyte.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh digibyte - -backend-deploy-and-test-dogecoin: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/dogecoin.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh dogecoin - -backend-deploy-and-test-litecoin: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/litecoin.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh litecoin - -backend-deploy-and-test-namecoin: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/namecoin.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh namecoin - -backend-deploy-and-test-vertcoin: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/vertcoin.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh vertcoin - -backend-deploy-and-test-zcash: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/zcash.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh zcash - -backend-deploy-and-test-bitcoin_testnet: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/bitcoin_testnet.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh bitcoin_testnet bitcoin-testnet bitcoin=test testnet3/debug.log - -backend-deploy-and-test-zcash_testnet: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/zcash_testnet.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh zcash_testnet zcash-testnet zcash=test testnet3/debug.log - -backend-deploy-and-test-ethereum_testnet_ropsten: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/ethereum_testnet_ropsten.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh ethereum_testnet_ropsten ethereum-testnet-ropsten ethereum=test ethereum_testnet_ropsten.log - -backend-deploy-and-test-syscoin: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/syscoin.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh syscoin - -backend-deploy-and-test-syscoin_testnet: - stage: backend-deploy-and-test - only: - refs: - - master - changes: - - configs/coins/syscoin_testnet.json - tags: - - blockbook - script: ./contrib/scripts/backend-deploy-and-test.sh syscoin_testnet syscoin-testnet syscoin=test testnet3/debug.log diff --git a/bchain/coins/eth/erc20.go b/bchain/coins/eth/erc20.go deleted file mode 100644 index 9870079c7e..0000000000 --- a/bchain/coins/eth/erc20.go +++ /dev/null @@ -1,245 +0,0 @@ -package eth - -import ( - "bytes" - "context" - "encoding/hex" - "math/big" - "strings" - "sync" - "unicode/utf8" - - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/golang/glog" - "github.com/juju/errors" - "github.com/syscoin/blockbook/bchain" -) - -var erc20abi = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function","signature":"0x06fdde03"}, -{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function","signature":"0x95d89b41"}, -{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function","signature":"0x313ce567"}, -{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function","signature":"0x18160ddd"}, -{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function","signature":"0x70a08231"}, -{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function","signature":"0xa9059cbb"}, -{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function","signature":"0x23b872dd"}, -{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function","signature":"0x095ea7b3"}, -{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function","signature":"0xdd62ed3e"}, -{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event","signature":"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"}, -{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event","signature":"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"}, -{"inputs":[{"name":"_initialAmount","type":"uint256"},{"name":"_tokenName","type":"string"},{"name":"_decimalUnits","type":"uint8"},{"name":"_tokenSymbol","type":"string"}],"payable":false,"type":"constructor"}, -{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function","signature":"0xcae9ca51"}, -{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function","signature":"0x54fd4d50"}]` - -// doing the parsing/processing without using go-ethereum/accounts/abi library, it is simple to get data from Transfer event -const erc20TransferMethodSignature = "0xa9059cbb" -const erc20TransferEventSignature = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" -const erc20NameSignature = "0x06fdde03" -const erc20SymbolSignature = "0x95d89b41" -const erc20DecimalsSignature = "0x313ce567" -const erc20BalanceOf = "0x70a08231" - -var cachedContracts = make(map[string]*bchain.Erc20Contract) -var cachedContractsMux sync.Mutex - -func addressFromPaddedHex(s string) (string, error) { - var t big.Int - var ok bool - if has0xPrefix(s) { - _, ok = t.SetString(s[2:], 16) - } else { - _, ok = t.SetString(s, 16) - } - if !ok { - return "", errors.New("Data is not a number") - } - a := ethcommon.BigToAddress(&t) - return a.String(), nil -} - -func erc20GetTransfersFromLog(logs []*rpcLog) ([]bchain.Erc20Transfer, error) { - var r []bchain.Erc20Transfer - for _, l := range logs { - if len(l.Topics) == 3 && l.Topics[0] == erc20TransferEventSignature { - var t big.Int - _, ok := t.SetString(l.Data, 0) - if !ok { - return nil, errors.New("Data is not a number") - } - from, err := addressFromPaddedHex(l.Topics[1]) - if err != nil { - return nil, err - } - to, err := addressFromPaddedHex(l.Topics[2]) - if err != nil { - return nil, err - } - r = append(r, bchain.Erc20Transfer{ - Contract: EIP55AddressFromAddress(l.Address), - From: EIP55AddressFromAddress(from), - To: EIP55AddressFromAddress(to), - Tokens: t, - }) - } - } - return r, nil -} - -func erc20GetTransfersFromTx(tx *rpcTransaction) ([]bchain.Erc20Transfer, error) { - var r []bchain.Erc20Transfer - if len(tx.Payload) == 128+len(erc20TransferMethodSignature) && strings.HasPrefix(tx.Payload, erc20TransferMethodSignature) { - to, err := addressFromPaddedHex(tx.Payload[len(erc20TransferMethodSignature) : 64+len(erc20TransferMethodSignature)]) - if err != nil { - return nil, err - } - var t big.Int - _, ok := t.SetString(tx.Payload[len(erc20TransferMethodSignature)+64:], 16) - if !ok { - return nil, errors.New("Data is not a number") - } - r = append(r, bchain.Erc20Transfer{ - Contract: EIP55AddressFromAddress(tx.To), - From: EIP55AddressFromAddress(tx.From), - To: EIP55AddressFromAddress(to), - Tokens: t, - }) - } - return r, nil -} - -func (b *EthereumRPC) ethCall(data, to string) (string, error) { - ctx, cancel := context.WithTimeout(context.Background(), b.timeout) - defer cancel() - var r string - err := b.rpc.CallContext(ctx, &r, "eth_call", map[string]interface{}{ - "data": data, - "to": to, - }, "latest") - if err != nil { - return "", err - } - return r, nil -} - -func parseErc20NumericProperty(contractDesc bchain.AddressDescriptor, data string) *big.Int { - if has0xPrefix(data) { - data = data[2:] - } - if len(data) > 64 { - data = data[:64] - } - if len(data) == 64 { - var n big.Int - _, ok := n.SetString(data, 16) - if ok { - return &n - } - } - if glog.V(1) { - glog.Warning("Cannot parse '", data, "' for contract ", contractDesc) - } - return nil -} - -func parseErc20StringProperty(contractDesc bchain.AddressDescriptor, data string) string { - if has0xPrefix(data) { - data = data[2:] - } - if len(data) > 128 { - n := parseErc20NumericProperty(contractDesc, data[64:128]) - if n != nil { - l := n.Uint64() - if l > 0 && 2*int(l) <= len(data)-128 { - b, err := hex.DecodeString(data[128 : 128+2*l]) - if err == nil { - return string(b) - } - } - } - } - // allow string properties as UTF-8 data - b, err := hex.DecodeString(data) - if err == nil { - i := bytes.Index(b, []byte{0}) - if i > 32 { - i = 32 - } - if i > 0 { - b = b[:i] - } - if utf8.Valid(b) { - return string(b) - } - } - if glog.V(1) { - glog.Warning("Cannot parse '", data, "' for contract ", contractDesc) - } - return "" -} - -// EthereumTypeGetErc20ContractInfo returns information about ERC20 contract -func (b *EthereumRPC) EthereumTypeGetErc20ContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.Erc20Contract, error) { - cds := string(contractDesc) - cachedContractsMux.Lock() - contract, found := cachedContracts[cds] - cachedContractsMux.Unlock() - if !found { - address := EIP55Address(contractDesc) - data, err := b.ethCall(erc20NameSignature, address) - if err != nil { - // ignore the error from the eth_call - since geth v1.9.15 they changed the behavior - // and returning error "execution reverted" for some non contract addresses - // https://github.com/ethereum/go-ethereum/issues/21249#issuecomment-648647672 - glog.Warning(errors.Annotatef(err, "erc20NameSignature %v", address)) - return nil, nil - // return nil, errors.Annotatef(err, "erc20NameSignature %v", address) - } - name := parseErc20StringProperty(contractDesc, data) - if name != "" { - data, err = b.ethCall(erc20SymbolSignature, address) - if err != nil { - glog.Warning(errors.Annotatef(err, "erc20SymbolSignature %v", address)) - return nil, nil - // return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address) - } - symbol := parseErc20StringProperty(contractDesc, data) - data, err = b.ethCall(erc20DecimalsSignature, address) - if err != nil { - glog.Warning(errors.Annotatef(err, "erc20DecimalsSignature %v", address)) - // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address) - } - contract = &bchain.Erc20Contract{ - Contract: address, - Name: name, - Symbol: symbol, - } - d := parseErc20NumericProperty(contractDesc, data) - if d != nil { - contract.Decimals = int(uint8(d.Uint64())) - } else { - contract.Decimals = EtherAmountDecimalPoint - } - } else { - contract = nil - } - cachedContractsMux.Lock() - cachedContracts[cds] = contract - cachedContractsMux.Unlock() - } - return contract, nil -} - -// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address -func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (*big.Int, error) { - addr := EIP55Address(addrDesc) - contract := EIP55Address(contractDesc) - req := erc20BalanceOf + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr)-2:] + addr[2:] - data, err := b.ethCall(req, contract) - if err != nil { - return nil, err - } - r := parseErc20NumericProperty(contractDesc, data) - if r == nil { - return nil, errors.New("Invalid balance") - } - return r, nil -} diff --git a/bchain/coins/eth/erc20_test.go b/bchain/coins/eth/erc20_test.go deleted file mode 100644 index 96879ff3fe..0000000000 --- a/bchain/coins/eth/erc20_test.go +++ /dev/null @@ -1,204 +0,0 @@ -//go:build unittest - -package eth - -import ( - "fmt" - "math/big" - "strings" - "testing" - - "github.com/syscoin/blockbook/bchain" - "github.com/syscoin/blockbook/tests/dbtestdata" -) - -func TestErc20_erc20GetTransfersFromLog(t *testing.T) { - tests := []struct { - name string - args []*rpcLog - want []bchain.Erc20Transfer - wantErr bool - }{ - { - name: "1", - args: []*rpcLog{ - { - Address: "0x76a45e8976499ab9ae223cc584019341d5a84e96", - Topics: []string{ - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - "0x0000000000000000000000002aacf811ac1a60081ea39f7783c0d26c500871a8", - "0x000000000000000000000000e9a5216ff992cfa01594d43501a56e12769eb9d2", - }, - Data: "0x0000000000000000000000000000000000000000000000000000000000000123", - }, - }, - want: []bchain.Erc20Transfer{ - { - Contract: "0x76a45e8976499ab9ae223cc584019341d5a84e96", - From: "0x2aacf811ac1a60081ea39f7783c0d26c500871a8", - To: "0xe9a5216ff992cfa01594d43501a56e12769eb9d2", - Tokens: *big.NewInt(0x123), - }, - }, - }, - { - name: "2", - args: []*rpcLog{ - { // Transfer - Address: "0x0d0f936ee4c93e25944694d6c121de94d9760f11", - Topics: []string{ - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - "0x0000000000000000000000006f44cceb49b4a5812d54b6f494fc2febf25511ed", - "0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d", - }, - Data: "0x0000000000000000000000000000000000000000000000006a8313d60b1f606b", - }, - { // Transfer - Address: "0xc778417e063141139fce010982780140aa0cd5ab", - Topics: []string{ - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - "0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d", - "0x0000000000000000000000006f44cceb49b4a5812d54b6f494fc2febf25511ed", - }, - Data: "0x000000000000000000000000000000000000000000000000000308fd0e798ac0", - }, - { // not Transfer - Address: "0x479cc461fecd078f766ecc58533d6f69580cf3ac", - Topics: []string{ - "0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3", - "0x0000000000000000000000006f44cceb49b4a5812d54b6f494fc2febf25511ed", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x5af266c0a89a07c1917deaa024414577e6c3c31c8907d079e13eb448c082594f", - }, - Data: "0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000", - }, - { // not Transfer - Address: "0x0d0f936ee4c93e25944694d6c121de94d9760f11", - Topics: []string{ - "0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3", - "0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b", - "0xb0b69dad58df6032c3b266e19b1045b19c87acd2c06fb0c598090f44b8e263aa", - }, - Data: "0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d000000000000000000000000c778417e063141139fce010982780140aa0cd5ab0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f1100000000000000000000000000000000000000000000000000031855667df7a80000000000000000000000000000000000000000000000006a8313d60b1f800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - }, - }, - want: []bchain.Erc20Transfer{ - { - Contract: "0x0d0f936ee4c93e25944694d6c121de94d9760f11", - From: "0x6f44cceb49b4a5812d54b6f494fc2febf25511ed", - To: "0x4bda106325c335df99eab7fe363cac8a0ba2a24d", - Tokens: *big.NewInt(0x6a8313d60b1f606b), - }, - { - Contract: "0xc778417e063141139fce010982780140aa0cd5ab", - From: "0x4bda106325c335df99eab7fe363cac8a0ba2a24d", - To: "0x6f44cceb49b4a5812d54b6f494fc2febf25511ed", - Tokens: *big.NewInt(0x308fd0e798ac0), - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := erc20GetTransfersFromLog(tt.args) - if (err != nil) != tt.wantErr { - t.Errorf("erc20GetTransfersFromLog error = %v, wantErr %v", err, tt.wantErr) - return - } - // the addresses could have different case - if strings.ToLower(fmt.Sprint(got)) != strings.ToLower(fmt.Sprint(tt.want)) { - t.Errorf("erc20GetTransfersFromLog = %+v, want %+v", got, tt.want) - } - }) - } -} - -func TestErc20_parseErc20StringProperty(t *testing.T) { - tests := []struct { - name string - args string - want string - }{ - { - name: "1", - args: "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000758504c4f44444500000000000000000000000000000000000000000000000000", - want: "XPLODDE", - }, - { - name: "2", - args: "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000022426974436c617665202d20436f6e73756d657220416374697669747920546f6b656e00000000000000", - want: "BitClave - Consumer Activity Token", - }, - { - name: "short", - args: "0x44616920537461626c65636f696e2076312e3000000000000000000000000000", - want: "Dai Stablecoin v1.0", - }, - { - name: "short2", - args: "0x44616920537461626c65636f696e2076312e3020444444444444444444444444", - want: "Dai Stablecoin v1.0 DDDDDDDDDDDD", - }, - { - name: "long", - args: "0x556e6973776170205631000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - want: "Uniswap V1", - }, - { - name: "garbage", - args: "0x2234880850896048596206002535425366538144616734015984380565810000", - want: "", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := parseErc20StringProperty(nil, tt.args) - // the addresses could have different case - if got != tt.want { - t.Errorf("parseErc20StringProperty = %v, want %v", got, tt.want) - } - }) - } -} - -func TestErc20_erc20GetTransfersFromTx(t *testing.T) { - p := NewEthereumParser(1) - b := dbtestdata.GetTestEthereumTypeBlock1(p) - bn, _ := new(big.Int).SetString("21e19e0c9bab2400000", 16) - tests := []struct { - name string - args *rpcTransaction - want []bchain.Erc20Transfer - }{ - { - name: "0", - args: (b.Txs[0].CoinSpecificData.(completeTransaction)).Tx, - want: []bchain.Erc20Transfer{}, - }, - { - name: "1", - args: (b.Txs[1].CoinSpecificData.(completeTransaction)).Tx, - want: []bchain.Erc20Transfer{ - { - Contract: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2", - From: "0x20cd153de35d469ba46127a0c8f18626b59a256a", - To: "0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f", - Tokens: *bn, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := erc20GetTransfersFromTx(tt.args) - if err != nil { - t.Errorf("erc20GetTransfersFromTx error = %v", err) - return - } - // the addresses could have different case - if strings.ToLower(fmt.Sprint(got)) != strings.ToLower(fmt.Sprint(tt.want)) { - t.Errorf("erc20GetTransfersFromTx = %+v, want %+v", got, tt.want) - } - }) - } -} diff --git a/build/docker/deb/gpg-keys/bitcoin-releases.asc b/build/docker/deb/gpg-keys/bitcoin-releases.asc deleted file mode 100644 index 69fc13e838..0000000000 --- a/build/docker/deb/gpg-keys/bitcoin-releases.asc +++ /dev/null @@ -1,280 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 - -mQINBFWKlBcBEACgZJd/6LrSgNSVxiyq5N9h0E7zgSHG/ahuWAnWeFtxaxHeukH+ -Q2Zq6F8FLbq40PphyroRylMBpzPBcyxjee7mDj1DpJ9ayv6GGPTyQzOImhChEV8p -bA42dvXnB5ju0rPh2GxctbiZZD1kiPH4jlmDIgomvupAj9OFntA5jfkuSFBekZrw -QyZowz/paMBIe24YH2LyaZjC2DqLy8Znh78OfAZxZsWSdZxK5LsbkCE9l8Li3gQa -rxm4aEMBHhvns+s8Ufa47sdJAYAfVnAWb5Dfe4oVFh70PvB8GSGFS9qeib0eEQBD -71c9MN+REDTSOYO2VnUSFbu7IrKsPsClqwfT9KzI/uz5fpHSKdCp5AO7oDZiU36s -LsSOBbukTmFQfVrAniFEZxHLCBufXCsAwp07xtUH9ytbW0Y/eHYlZojoWJJPT//1 -cQ/A2Ix/nxbSkSPq8wpCUhBxvTQoU9BXeQIbSy0yUmj5nS+3DR7IK2Q7ACyVClr7 -LVQOGxgZhHr9Kq87RDqc1wlvbCxb+KTJQhJySpOVoiaME6jLBzgE7G+5N6IXTK5u -OriOsQwcLdeBu7TPgft79uBYnmYeaNVdovlBB//7H7UvY0kAxAg4NPgK6eYRdzn+ -8ZtbntNXi/23RJvzeZJVBqQ7bYt4fjmHmRYrbM4jWKJEoJOE6wzpmELUowARAQAB -tFVXbGFkaW1pciBKLiB2YW4gZGVyIExhYW4gKEJpdGNvaW4gQ29yZSBiaW5hcnkg -cmVsZWFzZSBzaWduaW5nIGtleSkgPGxhYW53akBnbWFpbC5jb20+iQI+BBMBAgAo -BQJVipQXAhsDBQkDFwQABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCQyAGe -NsLpZOBRD/wLfujEC4ZYMFwPXnhvOGEWAPeuOg06iXhEqJ1biOvxhFfwwjPoXGMQ -i/pdfGck5xZVFcxObpdHBp0p9ardos1aRXAS8JTnTQXTX0qs0QNxnLTBz+5DrIc4 -l7r5DAlr/FapUKNSbjobOrbv+F371b7XhLJ7oob5XXo+IS7kEY+Si5BXb0uVy8ms -SaKDooO2RfByrFI3LTHW3VESuuNnXgH6309yeGORgBazKtnxZPPlD2raTNXe9q7U -dF2Xv6Rr53iCGGN5xncL5A6nF3fou0tGvqLFBkrs4BqeNNwC6/jQLfpOfqiQ+XGR -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 -oUudunjw+G1VG08DA3DMoougS9pC7x9k -=BFsn ------END PGP PUBLIC KEY BLOCK----- diff --git a/build/docker/deb/gpg-keys/groestlcoin-releases.asc b/build/docker/deb/gpg-keys/groestlcoin-releases.asc deleted file mode 100644 index e59835d2ae..0000000000 --- a/build/docker/deb/gpg-keys/groestlcoin-releases.asc +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -mQENBFxOL0ABCACnC4Im0MjbJpfoxWxkIWC9zugsjckwHC2UbXu5gFjtPbE6bXwK -IvhQeoHNPxuwm1dOWwWtJvoAoR+lOJqRMhvPM1DBcZe4Ht6XzzWnwx9WRP3lP99a -J2xOhdwNKv+HCVJ4tbwTTtkWuNWCMiUEjigoULTjKr1mecwoSEnQIRR0ciwxIpG/ -mO1SQdS96sujr3+70LTThIjgdOD1CA5GrwZSMctIPXEGXKXEQ4NL9/Zc8I5G9//y -8B+TiHTCpoIWfFbYw1GAUkLhswWV+rLNIYQzjxe3w9FD40+s1dU/1DzO2y2gib2n -G57RnwQ5V6i4axi7buWNzhWqGBXR6xxVIfN1ABEBAAG0J2phY2tpZWxvdmU0dSA8 -amFja2llbG92ZTR1QGhvdG1haWwuY29tPokBVAQTAQgAPhYhBCh65MoRh8aMCLSc -stEb1PM/HbSZBQJcTi9AAhsDBQkDwxhwBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheA -AAoJENEb1PM/HbSZFIgIAKaLGqXuahun8Nuds0c33ezqdT6vu4llAJSxX+dAg0Z0 -DKgski4jep1n94qvQXcoFhTcvXNxIv8YATzNx9JyM7SRVPQspr+g0hkzq75XfgsV -VqW8vPqAB1pdQoaSoK6wFljTA5DKifp7T8sJeNtReCjjSptszhdFaNllHAotz9qj -EoSHSnq8zlYKcVDnSqDEZozrbTohhWhc4V9VoNcYR8evNSdE8RCS+loVaPUIwANp -YK39Wxs0uE0j30iC/BY4b1ORP/fP7W3y8bgHscdQ5tEJa53iOFK3AYMhjc4ULZIz -i1z3rw1CcItWbuF5AbUTpnWRFG2uza6yRwZhcQyUBT+5AQ0EXE4vQAEIALv/X1oH -8r4uHfzkoQDrVvsjiGeTOVLbwNAqJGHzxWi2brVjlOdffmJGMRWS89trrveXWAIT -zjgFpkiZubOj/lS2+k5jE/IAakyX+eMUFULZt+6DF5oJBKTkdKaLi11dzJCPmaIv -fkNz3g68J9RlDJBFVLJzlaFGq6xZ1itbYDPrNjx98f7VhR2XbG/bise9heUpm9YJ -nJ8u5fjhbo10NNg6nwj7Huhwa+tuTHmQ/yPQ+dh8EeW78uwxrTRZ1DFTRTnFnBS6 -Q3jBI4cte8B0UWtcCZyXOXatShr/V5LTwH/Cxck2uu2X5tczhAWA1I3uZS5vUkJH -2kl1wWs54Xb/zMkAEQEAAYkBPAQYAQgAJhYhBCh65MoRh8aMCLScstEb1PM/HbSZ -BQJcTi9AAhsMBQkDwxhwAAoJENEb1PM/HbSZZ4gH/i3uRPk+x9ryedvADloY12uf -uv4GiJsIu4ZRvTiMrffMfSXl4W5G1Sp8IO2dKUs9pujrzOPPeYnxF/bILuCyve5v -kbbURwh7/gws6DOV75TmRDLyRhZktW1MWtKaF3ZQqndGgj2r8HWACCFJEYQCp2dN -UcIerVH9ZgmtsiZja4Kp1cf3SXu6xWLpg1DYhKAWfaGeK59ytP/D7BeIomuFp57i -lj0o/ThIqOunBQcaQaCSnpuXiPO6pOQZTaapj/xnGWlYcIowcKiUu/qgn4q/oh7P -oaBLoyLR9Orz09BuwAcpg5PaxV1HiprSU/wNW0cvS2DgdcfUZkYLb0MW6GC/9GA= -=7/m/ ------END PGP PUBLIC KEY BLOCK----- diff --git a/configs/coins/ethereum_testnet_ropsten.json b/configs/coins/ethereum_testnet_ropsten.json deleted file mode 100644 index 6d58b5c375..0000000000 --- a/configs/coins/ethereum_testnet_ropsten.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "coin": { - "name": "Ethereum Testnet Ropsten", - "shortcut": "tROP", - "label": "Ethereum Ropsten", - "alias": "ethereum_testnet_ropsten" - }, - "ports": { - "backend_rpc": 18036, - "backend_message_queue": 0, - "backend_p2p": 48336, - "blockbook_internal": 19036, - "blockbook_public": 19136 - }, - "ipc": { - "rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}", - "rpc_timeout": 25 - }, - "backend": { - "package_name": "backend-ethereum-testnet-ropsten", - "package_revision": "satoshilabs-1", - "system_user": "ethereum", - "version": "1.9.24-cc05b050", - "binary_url": "https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.9.24-cc05b050.tar.gz", - "verification_type": "gpg", - "verification_source": "https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.9.24-cc05b050.tar.gz.asc", - "extract_command": "tar -C backend --strip 1 -xf", - "exclude_files": [], - "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/geth --testnet --syncmode full --ipcdisable --cache 1024 --nat none --datadir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --port 48336 --ws --wsaddr 127.0.0.1 --wsport {{.Ports.BackendRPC}} --wsorigins \"*\" 2>>{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", - "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", - "postinst_script_template": "", - "service_type": "simple", - "service_additional_params_template": "", - "protect_memory": true, - "mainnet": false, - "server_config_file": "", - "client_config_file": "" - }, - "blockbook": { - "package_name": "blockbook-ethereum-testnet-ropsten", - "system_user": "blockbook-ethereum", - "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": 3000, - "additional_params": { - "mempoolTxTimeoutHours": 12, - "queryBackendOnMempoolResync": false - } - } - }, - "meta": { - "package_maintainer": "IT", - "package_maintainer_email": "it@satoshilabs.com" - } -} diff --git a/configs/coins/zelcash.json b/configs/coins/zelcash.json deleted file mode 100644 index c08cf2abd7..0000000000 --- a/configs/coins/zelcash.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "coin": { - "name": "ZelCash", - "shortcut": "ZEL", - "label": "ZelCash", - "alias": "zelcash" - }, - "ports": { - "backend_rpc": 8058, - "backend_message_queue": 38358, - "blockbook_internal": 9058, - "blockbook_public": 9158 - }, - "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-zelcash", - "package_revision": "satoshilabs-1", - "system_user": "zelcash", - "version": "4.0.0", - "binary_url": "https://github.com/zelcash/zelcash/releases/download/v4.0.0/Zel-Linux.tar.gz", - "verification_type": "sha256", - "verification_source": "72fc8edaf5b222e384fd3430babaf13cada8186f1aff84df28984212bc5ea66e", - "extract_command": "tar -C backend -xf", - "exclude_files": [], - "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/zelcashd -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": "HOME={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/fetch-params.sh", - "service_type": "forking", - "service_additional_params_template": "Environment=\"HOME={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend\"", - "protect_memory": false, - "mainnet": true, - "server_config_file": "bitcoin_like.conf", - "client_config_file": "bitcoin_like_client.conf", - "additional_params": { - "addnode": [ - "explorer.zel.cash", - "explorer2.zel.cash", - "explorer.zelcash.online", - "explorer-asia.zel.cash" - ] - } - }, - "blockbook": { - "package_name": "blockbook-zelcash", - "system_user": "blockbook-zelcash", - "internal_binding_template": ":{{.Ports.BlockbookInternal}}", - "public_binding_template": ":{{.Ports.BlockbookPublic}}", - "explorer_url": "", - "additional_params": "", - "block_chain": { - "parse": true, - "mempool_workers": 4, - "mempool_sub_workers": 8, - "block_addresses_to_keep": 300, - "xpub_magic": 76067358, - "slip44": 19167, - "additional_params": {} - } - }, - "meta": { - "package_maintainer": "Tadeas Kmenta", - "package_maintainer_email": "tadeas.kmenta@zel.cash" - } -} diff --git a/server/socketio.go b/server/socketio.go deleted file mode 100644 index 4ce9889428..0000000000 --- a/server/socketio.go +++ /dev/null @@ -1,946 +0,0 @@ -package server - -import ( - "encoding/json" - "math/big" - "net/http" - "runtime/debug" - "strconv" - "strings" - "time" - "fmt" - - "github.com/golang/glog" - "github.com/juju/errors" - gosocketio "github.com/martinboehm/golang-socketio" - "github.com/martinboehm/golang-socketio/transport" - "github.com/syscoin/blockbook/api" - "github.com/syscoin/blockbook/bchain" - "github.com/syscoin/blockbook/common" - "github.com/syscoin/blockbook/db" - ethcommon "github.com/ethereum/go-ethereum/common" -) - -// SocketIoServer is handle to SocketIoServer -type SocketIoServer struct { - server *gosocketio.Server - db *db.RocksDB - txCache *db.TxCache - chain bchain.BlockChain - chainParser bchain.BlockChainParser - mempool bchain.Mempool - metrics *common.Metrics - is *common.InternalState - api *api.Worker -} - -// NewSocketIoServer creates new SocketIo interface to blockbook and returns its handle -func NewSocketIoServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*SocketIoServer, error) { - api, err := api.NewWorker(db, chain, mempool, txCache, metrics, is) - if err != nil { - return nil, err - } - - server := gosocketio.NewServer(transport.GetDefaultWebsocketTransport()) - - server.On(gosocketio.OnConnection, func(c *gosocketio.Channel) { - glog.Info("Client connected ", c.Id()) - metrics.SocketIOClients.Inc() - }) - - server.On(gosocketio.OnDisconnection, func(c *gosocketio.Channel) { - glog.Info("Client disconnected ", c.Id()) - metrics.SocketIOClients.Dec() - }) - - server.On(gosocketio.OnError, func(c *gosocketio.Channel) { - glog.Error("Client error ", c.Id()) - }) - - type Message struct { - Name string `json:"name"` - Message string `json:"message"` - } - s := &SocketIoServer{ - server: server, - db: db, - txCache: txCache, - chain: chain, - chainParser: chain.GetChainParser(), - mempool: mempool, - metrics: metrics, - is: is, - api: api, - } - - server.On("message", s.onMessage) - server.On("subscribe", s.onSubscribe) - - return s, nil -} - -// GetHandler returns socket.io http handler -func (s *SocketIoServer) GetHandler() http.Handler { - return s.server -} - -type addrOpts struct { - Start int `json:"start"` - End int `json:"end"` - QueryMempoolOnly bool `json:"queryMempoolOnly"` - From int `json:"from"` - To int `json:"to"` -} - -type assetOpts struct { - Start int `json:"start"` - End int `json:"end"` - QueryMempoolOnly bool `json:"queryMempoolOnly"` - From int `json:"from"` - To int `json:"to"` - AssetsMask bchain.AssetsMask -} - -var onMessageHandlers = map[string]func(*SocketIoServer, json.RawMessage) (interface{}, error){ - "getAddressTxids": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - addr, opts, err := unmarshalGetAddressRequest(params) - if err == nil { - rv, err = s.getAddressTxids(addr, &opts) - } - return - }, - "getAddressHistory": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - addr, opts, err := unmarshalGetAddressRequest(params) - if err == nil { - rv, err = s.getAddressHistory(addr, &opts) - } - return - }, - "getAssetTxids": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - asset, opts, err := unmarshalGetAssetRequest(params) - if err == nil { - rv, err = s.getAssetTxids(asset, &opts) - } - return - }, - "getAssetHistory": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - asset, opts, err := unmarshalGetAssetRequest(params) - if err == nil { - rv, err = s.getAssetHistory(asset, &opts) - } - return - }, - "getBlockHeader": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - height, hash, err := unmarshalGetBlockHeader(params) - if err == nil { - rv, err = s.getBlockHeader(height, hash) - } - return - }, - "estimateSmartFee": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - blocks, conservative, err := unmarshalEstimateSmartFee(params) - if err == nil { - rv, err = s.estimateSmartFee(blocks, conservative) - } - return - }, - "estimateFee": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - blocks, err := unmarshalEstimateFee(params) - if err == nil { - rv, err = s.estimateFee(blocks) - } - return - }, - "getInfo": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - return s.getInfo() - }, - "getDetailedTransaction": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - txid, err := unmarshalGetDetailedTransaction(params) - if err == nil { - rv, err = s.getDetailedTransaction(txid) - } - return - }, - "sendTransaction": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - tx, err := unmarshalStringParameter(params) - if err == nil { - rv, err = s.sendTransaction(tx) - } - return - }, - "getMempoolEntry": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) { - txid, err := unmarshalStringParameter(params) - if err == nil { - rv, err = s.getMempoolEntry(txid) - } - return - }, -} - -type resultError struct { - Error struct { - Message string `json:"message"` - } `json:"error"` -} - -func (s *SocketIoServer) onMessage(c *gosocketio.Channel, req map[string]json.RawMessage) (rv interface{}) { - var err error - method := strings.Trim(string(req["method"]), "\"") - defer func() { - if r := recover(); r != nil { - glog.Error(c.Id(), " onMessage ", method, " recovered from panic: ", r) - debug.PrintStack() - e := resultError{} - e.Error.Message = "Internal error" - rv = e - } - s.metrics.SocketIOPendingRequests.With((common.Labels{"method": method})).Dec() - }() - t := time.Now() - params := req["params"] - s.metrics.SocketIOPendingRequests.With((common.Labels{"method": method})).Inc() - defer s.metrics.SocketIOReqDuration.With(common.Labels{"method": method}).Observe(float64(time.Since(t)) / 1e3) // in microseconds - f, ok := onMessageHandlers[method] - if ok { - rv, err = f(s, params) - } else { - err = errors.New("unknown method") - } - if err == nil { - glog.V(1).Info(c.Id(), " onMessage ", method, " success") - s.metrics.SocketIORequests.With(common.Labels{"method": method, "status": "success"}).Inc() - return rv - } - glog.Error(c.Id(), " onMessage ", method, ": ", errors.ErrorStack(err), ", data ", string(params)) - s.metrics.SocketIORequests.With(common.Labels{"method": method, "status": "failure"}).Inc() - e := resultError{} - e.Error.Message = err.Error() - return e -} - -func unmarshalGetAddressRequest(params []byte) (addr []string, opts addrOpts, err error) { - var p []json.RawMessage - err = json.Unmarshal(params, &p) - if err != nil { - return - } - if len(p) != 2 { - err = errors.New("incorrect number of parameters") - return - } - err = json.Unmarshal(p[0], &addr) - if err != nil { - return - } - err = json.Unmarshal(p[1], &opts) - return -} - -func unmarshalGetAssetRequest(params []byte) (asset string, opts assetOpts, err error) { - var p []json.RawMessage - err = json.Unmarshal(params, &p) - if err != nil { - return - } - if len(p) != 2 { - err = errors.New("incorrect number of parameters") - return - } - err = json.Unmarshal(p[0], &asset) - if err != nil { - return - } - err = json.Unmarshal(p[1], &opts) - return -} - -type resultAddressTxids struct { - Result []string `json:"result"` -} - -func (s *SocketIoServer) getAddressTxids(addr []string, opts *addrOpts) (res resultAddressTxids, err error) { - txids := make([]string, 0, 8) - lower, higher := uint32(opts.End), uint32(opts.Start) - for _, address := range addr { - if !opts.QueryMempoolOnly { - err = s.db.GetTransactions(address, lower, higher, func(txid string, height uint32, assetGuid []uint64, indexes []int32) error { - txids = append(txids, txid) - return nil - }) - if err != nil { - return res, err - } - } else { - o, err := s.mempool.GetTransactions(address) - if err != nil { - return res, err - } - for _, m := range o { - txids = append(txids, m.Txid) - } - } - } - res.Result = api.GetUniqueTxids(txids) - return res, nil -} - -func (s *SocketIoServer) getAssetTxids(asset string, opts *assetOpts) (res resultAddressTxids, err error) { - txids := make([]string, 0, 8) - lower, higher := uint32(opts.End), uint32(opts.Start) - assetBitMask := opts.AssetsMask - assetGuid, err := strconv.ParseUint(asset, 10, 64) - if err != nil { - return res, err - } - if !opts.QueryMempoolOnly { - err = s.db.GetTxAssets(assetGuid, lower, higher, assetBitMask, func(txidsIn []string) error { - txids = append(txids, txidsIn...) - return nil - }) - if err != nil { - return res, err - } - } else { - o := s.mempool.GetTxAssets(assetGuid) - for _, m := range o { - txids = append(txids, m.Txid) - } - } - res.Result = api.GetUniqueTxids(txids) - return res, nil -} - -type addressHistoryIndexes struct { - InputIndexes []int `json:"inputIndexes"` - OutputIndexes []int `json:"outputIndexes"` -} - -type txInputs struct { - Txid *string `json:"txid"` - OutputIndex int `json:"outputIndex"` - Script *string `json:"script"` - // ScriptAsm *string `json:"scriptAsm"` - Sequence int64 `json:"sequence"` - Address *string `json:"address"` - Satoshis int64 `json:"satoshis"` -} - -type txOutputs struct { - Satoshis int64 `json:"satoshis"` - Script *string `json:"script"` - // ScriptAsm *string `json:"scriptAsm"` - // SpentTxID *string `json:"spentTxId,omitempty"` - // SpentIndex int `json:"spentIndex,omitempty"` - // SpentHeight int `json:"spentHeight,omitempty"` - Address *string `json:"address"` -} - -type resTx struct { - Hex string `json:"hex"` - // BlockHash string `json:"blockHash,omitempty"` - Height int `json:"height"` - BlockTimestamp int64 `json:"blockTimestamp,omitempty"` - Version int `json:"version"` - Hash string `json:"hash"` - Locktime int `json:"locktime,omitempty"` - // Size int `json:"size,omitempty"` - Inputs []txInputs `json:"inputs"` - InputSatoshis int64 `json:"inputSatoshis,omitempty"` - Outputs []txOutputs `json:"outputs"` - OutputSatoshis int64 `json:"outputSatoshis,omitempty"` - FeeSatoshis int64 `json:"feeSatoshis,omitempty"` - TokenTransferSummary []*bchain.TokenTransferSummary `json:"tokenTransfers,omitempty"` -} - -type addressHistoryItem struct { - Addresses map[string]*addressHistoryIndexes `json:"addresses"` - Satoshis int64 `json:"satoshis"` - Confirmations int `json:"confirmations"` - Tx resTx `json:"tx"` - Tokens map[string]*api.TokenBalanceHistory `json:"tokens,omitempty"` -} - -type resultGetAddressHistory struct { - Result struct { - TotalCount int `json:"totalCount"` - Items []addressHistoryItem `json:"items"` - } `json:"result"` -} -type resultGetAssetHistory struct { - Result struct { - TotalCount int `json:"totalCount"` - AssetDetails *api.AssetSpecific `json:"asset"` - Items []addressHistoryItem `json:"items"` - } `json:"result"` -} -func txToResTx(tx *api.Tx) resTx { - var resultTx resTx - inputs := make([]txInputs, len(tx.Vin)) - for i := range tx.Vin { - vin := &tx.Vin[i] - txid := vin.Txid - script := vin.Hex - input := txInputs{ - Txid: &txid, - Script: &script, - Sequence: int64(vin.Sequence), - OutputIndex: int(vin.Vout), - Satoshis: vin.ValueSat.AsInt64(), - } - if len(vin.Addresses) > 0 { - a := vin.Addresses[0] - input.Address = &a - } - inputs[i] = input - } - outputs := make([]txOutputs, len(tx.Vout)) - for i := range tx.Vout { - vout := &tx.Vout[i] - script := vout.Hex - output := txOutputs{ - Satoshis: vout.ValueSat.AsInt64(), - Script: &script, - } - if len(vout.Addresses) > 0 { - a := vout.Addresses[0] - output.Address = &a - } - outputs[i] = output - } - if len(tx.TokenTransferSummary) > 0 { - resultTx.TokenTransferSummary = tx.TokenTransferSummary - } - var h int - var blocktime int64 - if tx.Confirmations == 0 { - h = -1 - } else { - h = int(tx.Blockheight) - blocktime = tx.Blocktime - } - resultTx.BlockTimestamp = blocktime - resultTx.FeeSatoshis = tx.FeesSat.AsInt64() - resultTx.Hash = tx.Txid - resultTx.Height = h - resultTx.Hex = tx.Hex - resultTx.Inputs = inputs - resultTx.InputSatoshis = tx.ValueInSat.AsInt64() - resultTx.Locktime = int(tx.Locktime) - resultTx.Outputs = outputs - resultTx.OutputSatoshis = tx.ValueOutSat.AsInt64() - resultTx.Version = int(tx.Version) - return resultTx -} - -func addressInSlice(s, t []string) string { - for _, sa := range s { - for _, ta := range t { - if ta == sa { - return sa - } - } - } - return "" -} - -func (s *SocketIoServer) getAddressesFromVout(vout *bchain.Vout) ([]string, error) { - addrDesc, err := s.chainParser.GetAddrDescFromVout(vout) - if err != nil { - return nil, err - } - voutAddr, _, err := s.chainParser.GetAddressesFromAddrDesc(addrDesc) - if err != nil { - return nil, err - } - return voutAddr, nil -} - -func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res resultGetAddressHistory, err error) { - txr, err := s.getAddressTxids(addr, opts) - if err != nil { - return - } - txids := txr.Result - res.Result.TotalCount = len(txids) - res.Result.Items = make([]addressHistoryItem, 0, 8) - to := len(txids) - if to > opts.To { - to = opts.To - } - ahi := addressHistoryItem{} - for txi := opts.From; txi < to; txi++ { - tx, err := s.api.GetTransaction(txids[txi], false, false) - if err != nil { - return res, err - } - ads := make(map[string]*addressHistoryIndexes) - var totalSat big.Int - for i := range tx.Vin { - vin := &tx.Vin[i] - a := addressInSlice(vin.Addresses, addr) - if a != "" { - hi := ads[a] - if hi == nil { - hi = &addressHistoryIndexes{OutputIndexes: []int{}} - ads[a] = hi - } - hi.InputIndexes = append(hi.InputIndexes, int(vin.N)) - if vin.ValueSat != nil { - totalSat.Sub(&totalSat, (*big.Int)(vin.ValueSat)) - } - if vin.AssetInfo != nil { - if ahi.Tokens == nil { - ahi.Tokens = map[string]*api.TokenBalanceHistory{} - } - token, ok := ahi.Tokens[vin.AssetInfo.AssetGuid] - if !ok { - token = &api.TokenBalanceHistory{ReceivedSat: &bchain.Amount{}, SentSat: &bchain.Amount{}} - ahi.Tokens[vin.AssetInfo.AssetGuid] = token - } - (*big.Int)(token.SentSat).Add((*big.Int)(token.SentSat), (*big.Int)(vin.AssetInfo.ValueSat)) - } - } - } - for i := range tx.Vout { - vout := &tx.Vout[i] - a := addressInSlice(vout.Addresses, addr) - if a != "" { - hi := ads[a] - if hi == nil { - hi = &addressHistoryIndexes{InputIndexes: []int{}} - ads[a] = hi - } - hi.OutputIndexes = append(hi.OutputIndexes, int(vout.N)) - if vout.ValueSat != nil { - totalSat.Add(&totalSat, (*big.Int)(vout.ValueSat)) - } - if vout.AssetInfo != nil { - if ahi.Tokens == nil { - ahi.Tokens = map[string]*api.TokenBalanceHistory{} - } - token, ok := ahi.Tokens[vout.AssetInfo.AssetGuid] - if !ok { - token = &api.TokenBalanceHistory{ReceivedSat: &bchain.Amount{}, SentSat: &bchain.Amount{}} - ahi.Tokens[vout.AssetInfo.AssetGuid] = token - } - (*big.Int)(token.ReceivedSat).Add((*big.Int)(token.ReceivedSat), (*big.Int)(vout.AssetInfo.ValueSat)) - } - } - } - ahi.Addresses = ads - ahi.Confirmations = int(tx.Confirmations) - ahi.Satoshis = totalSat.Int64() - ahi.Tx = txToResTx(tx) - res.Result.Items = append(res.Result.Items, ahi) - // } - } - return -} -func (s *SocketIoServer) getAssetHistory(assetGuid string, opts *assetOpts) (res resultGetAssetHistory, err error) { - txr, err := s.getAssetTxids(assetGuid, opts) - if err != nil { - return res, err - } - txids := txr.Result - res.Result.TotalCount = len(txids) - res.Result.Items = make([]addressHistoryItem, 0, 8) - to := len(txids) - if to > opts.To { - to = opts.To - } - ahi := addressHistoryItem{} - ahi.Tokens = map[string]*api.TokenBalanceHistory{} - for txi := opts.From; txi < to; txi++ { - tx, err := s.api.GetTransaction(txids[txi], false, false) - if err != nil { - return res, err - } - ads := make(map[string]*addressHistoryIndexes) - var totalSat big.Int - for i := range tx.Vin { - vin := &tx.Vin[i] - if vin.AssetInfo != nil && vin.AssetInfo.AssetGuid == assetGuid { - a, _, err := s.chainParser.GetAddressesFromAddrDesc(vin.AddrDesc) - if err != nil { - return res, err - } - for _, addr := range a { - hi := ads[addr] - if hi == nil { - hi = &addressHistoryIndexes{OutputIndexes: []int{}} - ads[addr] = hi - } - hi.InputIndexes = append(hi.InputIndexes, int(vin.N)) - } - if vin.ValueSat != nil { - totalSat.Sub(&totalSat, (*big.Int)(vin.ValueSat)) - } - token, ok := ahi.Tokens[vin.AssetInfo.AssetGuid] - if !ok { - token = &api.TokenBalanceHistory{ReceivedSat: &bchain.Amount{}, SentSat: &bchain.Amount{}} - ahi.Tokens[vin.AssetInfo.AssetGuid] = token - } - (*big.Int)(token.SentSat).Add((*big.Int)(token.SentSat), (*big.Int)(vin.AssetInfo.ValueSat)) - } - } - for i := range tx.Vout { - vout := &tx.Vout[i] - if vout.AssetInfo != nil && vout.AssetInfo.AssetGuid == assetGuid { - a, _, err := s.chainParser.GetAddressesFromAddrDesc(vout.AddrDesc) - if err != nil { - return res, err - } - for _, addr := range a { - hi := ads[addr] - if hi == nil { - hi = &addressHistoryIndexes{InputIndexes: []int{}} - ads[addr] = hi - } - hi.OutputIndexes = append(hi.OutputIndexes, int(vout.N)) - } - if vout.ValueSat != nil { - totalSat.Add(&totalSat, (*big.Int)(vout.ValueSat)) - } - - token, ok := ahi.Tokens[vout.AssetInfo.AssetGuid] - if !ok { - token = &api.TokenBalanceHistory{ReceivedSat: &bchain.Amount{}, SentSat: &bchain.Amount{}} - ahi.Tokens[vout.AssetInfo.AssetGuid] = token - } - (*big.Int)(token.ReceivedSat).Add((*big.Int)(token.ReceivedSat), (*big.Int)(vout.AssetInfo.ValueSat)) - - } - } - ahi.Addresses = ads - assetGuidInt, err := strconv.ParseUint(assetGuid, 10, 64) - if err != nil { - return res, err - } - dbAsset, errAsset := s.db.GetAsset(assetGuidInt, nil) - if errAsset != nil { - return res, errors.New(fmt.Sprintf("getAssetHistory Asset not found err: %v", errAsset)) - } - if len(ahi.Tokens) <= 0 { - ahi.Tokens = nil - } - ahi.Confirmations = int(tx.Confirmations) - ahi.Satoshis = totalSat.Int64() - ahi.Tx = txToResTx(tx) - res.Result.AssetDetails = &api.AssetSpecific{ - AssetGuid: assetGuid, - Symbol: string(dbAsset.AssetObj.Symbol), - Contract: ethcommon.BytesToAddress(dbAsset.AssetObj.Contract).Hex(), - TotalSupply: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.TotalSupply)), - MaxSupply: (*bchain.Amount)(big.NewInt(dbAsset.AssetObj.MaxSupply)), - Decimals: int(dbAsset.AssetObj.Precision), - } - res.Result.Items = append(res.Result.Items, ahi) - // } - } - return -} - -func unmarshalArray(params []byte, np int) (p []interface{}, err error) { - err = json.Unmarshal(params, &p) - if err != nil { - return - } - if len(p) != np { - err = errors.New("incorrect number of parameters") - return - } - return -} - -func unmarshalGetBlockHeader(params []byte) (height uint32, hash string, err error) { - p, err := unmarshalArray(params, 1) - if err != nil { - return - } - fheight, ok := p[0].(float64) - if ok { - return uint32(fheight), "", nil - } - hash, ok = p[0].(string) - if ok { - return - } - err = errors.New("incorrect parameter") - return -} - -type resultGetBlockHeader struct { - Result struct { - Hash string `json:"hash"` - Version int `json:"version"` - Confirmations int `json:"confirmations"` - Height int `json:"height"` - ChainWork string `json:"chainWork"` - NextHash string `json:"nextHash"` - MerkleRoot string `json:"merkleRoot"` - Time int `json:"time"` - MedianTime int `json:"medianTime"` - Nonce int `json:"nonce"` - Bits string `json:"bits"` - Difficulty float64 `json:"difficulty"` - } `json:"result"` -} - -func (s *SocketIoServer) getBlockHeader(height uint32, hash string) (res resultGetBlockHeader, err error) { - if hash == "" { - // trezor is interested only in hash - hash, err = s.db.GetBlockHash(height) - if err != nil { - return - } - res.Result.Hash = hash - return - } - bh, err := s.chain.GetBlockHeader(hash) - if err != nil { - return - } - res.Result.Hash = bh.Hash - res.Result.Confirmations = bh.Confirmations - res.Result.Height = int(bh.Height) - res.Result.NextHash = bh.Next - return -} - -func unmarshalEstimateSmartFee(params []byte) (blocks int, conservative bool, err error) { - p, err := unmarshalArray(params, 2) - if err != nil { - return - } - fblocks, ok := p[0].(float64) - if !ok { - err = errors.New("Invalid parameter blocks") - return - } - blocks = int(fblocks) - conservative, ok = p[1].(bool) - if !ok { - err = errors.New("Invalid parameter conservative") - return - } - return -} - -type resultEstimateSmartFee struct { - // for compatibility reasons use float64 - Result float64 `json:"result"` -} - -func (s *SocketIoServer) estimateSmartFee(blocks int, conservative bool) (res resultEstimateSmartFee, err error) { - fee, err := s.chain.EstimateSmartFee(blocks, conservative) - if err != nil { - return - } - res.Result, err = strconv.ParseFloat(s.chainParser.AmountToDecimalString(&fee), 64) - return -} - -func unmarshalEstimateFee(params []byte) (blocks int, err error) { - p, err := unmarshalArray(params, 1) - if err != nil { - return - } - fblocks, ok := p[0].(float64) - if !ok { - err = errors.New("Invalid parameter nblocks") - return - } - blocks = int(fblocks) - return -} - -type resultEstimateFee struct { - // for compatibility reasons use float64 - Result float64 `json:"result"` -} - -func (s *SocketIoServer) estimateFee(blocks int) (res resultEstimateFee, err error) { - fee, err := s.chain.EstimateFee(blocks) - if err != nil { - return - } - res.Result, err = strconv.ParseFloat(s.chainParser.AmountToDecimalString(&fee), 64) - return -} - -type resultGetInfo struct { - Result struct { - Version int `json:"version,omitempty"` - ProtocolVersion int `json:"protocolVersion,omitempty"` - Blocks int `json:"blocks"` - TimeOffset int `json:"timeOffset,omitempty"` - Connections int `json:"connections,omitempty"` - Proxy string `json:"proxy,omitempty"` - Difficulty float64 `json:"difficulty,omitempty"` - Testnet bool `json:"testnet"` - RelayFee float64 `json:"relayFee,omitempty"` - Errors string `json:"errors,omitempty"` - Network string `json:"network,omitempty"` - Subversion string `json:"subversion,omitempty"` - LocalServices string `json:"localServices,omitempty"` - CoinName string `json:"coin_name,omitempty"` - About string `json:"about,omitempty"` - } `json:"result"` -} - -func (s *SocketIoServer) getInfo() (res resultGetInfo, err error) { - _, height, _ := s.is.GetSyncState() - res.Result.Blocks = int(height) - res.Result.Testnet = s.chain.IsTestnet() - res.Result.Network = s.chain.GetNetworkName() - res.Result.Subversion = s.chain.GetSubversion() - res.Result.CoinName = s.chain.GetCoinName() - res.Result.About = api.Text.BlockbookAbout - return -} - -func unmarshalStringParameter(params []byte) (s string, err error) { - p, err := unmarshalArray(params, 1) - if err != nil { - return - } - s, ok := p[0].(string) - if ok { - return - } - err = errors.New("incorrect parameter") - return -} - -func unmarshalGetDetailedTransaction(params []byte) (txid string, err error) { - var p []json.RawMessage - err = json.Unmarshal(params, &p) - if err != nil { - return - } - if len(p) != 1 { - err = errors.New("incorrect number of parameters") - return - } - err = json.Unmarshal(p[0], &txid) - if err != nil { - return - } - return -} - -type resultGetDetailedTransaction struct { - Result resTx `json:"result"` -} - -func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetailedTransaction, err error) { - tx, err := s.api.GetTransaction(txid, false, false) - if err != nil { - return res, err - } - res.Result = txToResTx(tx) - return -} - -func (s *SocketIoServer) sendTransaction(tx string) (res resultSendTransaction, err error) { - txid, err := s.chain.SendRawTransaction(tx) - if err != nil { - return res, err - } - res.Result = txid - return -} - -type resultGetMempoolEntry struct { - Result *bchain.MempoolEntry `json:"result"` -} - -func (s *SocketIoServer) getMempoolEntry(txid string) (res resultGetMempoolEntry, err error) { - entry, err := s.chain.GetMempoolEntry(txid) - if err != nil { - return res, err - } - res.Result = entry - return -} - -// onSubscribe expects two event subscriptions based on the req parameter (including the doublequotes): -// "bitcoind/hashblock" -// "bitcoind/addresstxid",["2MzTmvPJLZaLzD9XdN3jMtQA5NexC3rAPww","2NAZRJKr63tSdcTxTN3WaE9ZNDyXy6PgGuv"] -func (s *SocketIoServer) onSubscribe(c *gosocketio.Channel, req []byte) interface{} { - defer func() { - if r := recover(); r != nil { - glog.Error(c.Id(), " onSubscribe recovered from panic: ", r) - debug.PrintStack() - } - }() - - onError := func(id, sc, err, detail string) { - glog.Error(id, " onSubscribe ", err, ": ", detail) - s.metrics.SocketIOSubscribes.With(common.Labels{"channel": sc, "status": "failure"}).Inc() - } - - r := string(req) - glog.V(1).Info(c.Id(), " onSubscribe ", r) - var sc string - i := strings.Index(r, "\",[") - if i > 0 { - var addrs []string - sc = r[1:i] - if sc != "bitcoind/addresstxid" { - onError(c.Id(), sc, "invalid data", "expecting bitcoind/addresstxid, req: "+r) - return nil - } - err := json.Unmarshal([]byte(r[i+2:]), &addrs) - if err != nil { - onError(c.Id(), sc, "invalid data", err.Error()+", req: "+r) - return nil - } - // normalize the addresses to AddressDescriptor - descs := make([]bchain.AddressDescriptor, len(addrs)) - for i, a := range addrs { - d, err := s.chainParser.GetAddrDescFromAddress(a) - if err != nil { - onError(c.Id(), sc, "invalid address "+a, err.Error()+", req: "+r) - return nil - } - descs[i] = d - } - for _, d := range descs { - c.Join("bitcoind/addresstxid-" + string(d)) - } - } else { - sc = r[1 : len(r)-1] - if sc != "bitcoind/hashblock" { - onError(c.Id(), sc, "invalid data", "expecting bitcoind/hashblock, req: "+r) - return nil - } - c.Join(sc) - } - s.metrics.SocketIOSubscribes.With(common.Labels{"channel": sc, "status": "success"}).Inc() - return nil -} - -func (s *SocketIoServer) onNewBlockHashAsync(hash string) { - c := s.server.BroadcastTo("bitcoind/hashblock", "bitcoind/hashblock", hash) - glog.Info("broadcasting new block hash ", hash, " to ", c, " channels") -} - -// OnNewBlockHash notifies users subscribed to bitcoind/hashblock about new block -func (s *SocketIoServer) OnNewBlockHash(hash string) { - go s.onNewBlockHashAsync(hash) -} - -// OnNewTxAddr notifies users subscribed to bitcoind/addresstxid about new block -func (s *SocketIoServer) OnNewTxAddr(txid string, desc bchain.AddressDescriptor) { - addr, searchable, err := s.chainParser.GetAddressesFromAddrDesc(desc) - if err != nil { - glog.Error("GetAddressesFromAddrDesc error ", err, " for descriptor ", desc) - } else if searchable && len(addr) == 1 { - data := map[string]interface{}{"address": addr[0], "txid": txid} - c := s.server.BroadcastTo("bitcoind/addresstxid-"+string(desc), "bitcoind/addresstxid", data) - if c > 0 { - glog.Info("broadcasting new txid ", txid, " for addr ", addr[0], " to ", c, " channels") - } - } -} diff --git a/static/templates/tx.html b/static/templates/tx.html deleted file mode 100644 index fd1926c5f0..0000000000 --- a/static/templates/tx.html +++ /dev/null @@ -1,142 +0,0 @@ -{{define "specific"}}{{$cs := .CoinShortcut}}{{$tx := .Tx}} -

Transaction

-
- {{$tx.Txid}} -
-

Summary

-
- - - {{- if $tx.Confirmations -}} - - - - {{end -}} - - - - - {{- if $tx.Confirmations -}} - - - - {{end}} - {{- if $tx.EthereumSpecific -}} - - - {{- if $tx.EthereumSpecific.Status -}} - {{- if eq $tx.EthereumSpecific.Status 1 -}} - - {{- else -}} - {{- if eq $tx.EthereumSpecific.Status -1 -}} - - {{- else -}} - - {{- end -}} - {{- end -}} - {{- else -}} - - {{- end -}} - - - - - - - - - - - - - - {{- else -}} - - - - - - - - - {{- end -}} - {{- if $tx.FeesSat -}} - - - - {{end -}} - {{if gt (len $tx.Memo) 0}} - - - - {{end}} - {{- if $tx.TokenTransferSummary -}} - - - - - {{- end -}} - {{- if not $tx.Confirmations}} - - - - - {{end -}} - -
Mined Time{{formatUnixTime $tx.Blocktime}}
In Block{{if $tx.Confirmations}}{{$tx.Blockhash}}{{else}}Unconfirmed{{end}}
In Block Height{{$tx.Blockheight}}
StatusSuccessPendingUnknownFail
Value{{formatAmount $tx.ValueOutSat}} {{$cs}}
Gas Used / Limit{{if $tx.EthereumSpecific.GasUsed}}{{$tx.EthereumSpecific.GasUsed}}{{else}}pending{{end}} / {{$tx.EthereumSpecific.GasLimit}}
Gas Price{{formatAmount $tx.EthereumSpecific.GasPrice}} {{$cs}}
Total Input{{formatAmount $tx.ValueInSat}} {{$cs}}
Total Output{{formatAmount $tx.ValueOutSat}} {{$cs}}
Fees{{formatAmount $tx.FeesSat}} {{$cs}}
Memo{{formatEncodeBase64 $tx.Memo}}
Tokens - - - - - - - {{- range $tokenTransfer := $tx.TokenTransferSummary -}}{{if $tokenTransfer}} - - - - - {{- end -}}{{- end -}} - -
AssetTotal
{{$tokenTransfer.Token}} {{$tokenTransfer.Symbol}}{{formatAmountWithDecimals $tokenTransfer.Value $tokenTransfer.Decimals}} {{$tokenTransfer.Symbol}}
-
RBF - {{- if $tx.Rbf}} - ON - {{- else -}} - OFF️ - {{end -}} -
-
-

Details

-
- {{template "txdetail" .}} -
-
-
Raw Transaction
-
-

-    
- -
-{{end}} diff --git a/static/test-socketio.html b/static/test-socketio.html deleted file mode 100644 index 586525ad7f..0000000000 --- a/static/test-socketio.html +++ /dev/null @@ -1,522 +0,0 @@ - - - - - - - - - - Blockbook Socket.io Test Page - - - - -
-
-

Blockbook Socket.io Test Page

-
-
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
-   - -
-
-
-
-
-
-
-
- -
-
-
- - - -
-
-
-   - -
-
-
-
-
-
-
-
- -
-
- -
-
-   - -
-
-
-
-
-
-
-
- -
-
-
- - - -
-
-
-   - -
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-   - -
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
- - - - \ No newline at end of file diff --git a/tests/rpc/testdata/zcoin.json b/tests/rpc/testdata/zcoin.json deleted file mode 100644 index 1d5f224a88..0000000000 --- a/tests/rpc/testdata/zcoin.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "blockHeight": 126311, - "blockHash": "4857051323dd6a10bc1c92facb00e7c8258adc9b8b680d0bcdd19034a777d72d", - "blockTime": 1547120622, - "blockTxs": [ - "5ee3ba91195adc9a22e61a570b168052764584305000450d04355ebcb9cc4be8", - "2f831477d523ea717caf9a9520dd848b8fe932540207037fabf100a56d466e91", - "347d7c8c1d77f2f835641be27d97900f88be71646bdaa14ffb11b37aaac72f79" - ], - "txDetails": { - "2f831477d523ea717caf9a9520dd848b8fe932540207037fabf100a56d466e91": { - "hex": "010000000106be6afc693eb158fa010f751c347982851108ea316d0685109caaa8ec4580c2000000006a473044022048dcdd1121148ecf495df74f563384d91db0635dae3c608666511ef8f24adc19022004af5384be1bce1531d0bf8498a8bfb150f797e63e348ca3865f0322203384aa012102d79d7e7f40e091517465c50ed3f5345c7b9a4611a98103ee1ca1f8e66686ad9fffffffff02e04d6cb3160000001976a914b923050a6542d70d6eb6546ba3275a2b6ea0eda588ac06d8c849000000001976a914c353c188620cb33a72d218c0d67fb3f92ad1b6b088ac00000000", - "txid": "2f831477d523ea717caf9a9520dd848b8fe932540207037fabf100a56d466e91", - "blocktime": 1547120622, - "time": 1547120622, - "locktime": 0, - "version": 1, - "vin": [ - { - "txid": "c28045eca8aa9c1085066d31ea0811858279341c750f01fa58b13e69fc6abe06", - "vout": 0, - "sequence": 4294967295, - "scriptSig": { - "hex": "473044022048dcdd1121148ecf495df74f563384d91db0635dae3c608666511ef8f24adc19022004af5384be1bce1531d0bf8498a8bfb150f797e63e348ca3865f0322203384aa012102d79d7e7f40e091517465c50ed3f5345c7b9a4611a98103ee1ca1f8e66686ad9f" - } - } - ], - "vout": [ - { - "value": 974.99500000, - "n": 0, - "scriptPubKey": { - "hex": "76a914b923050a6542d70d6eb6546ba3275a2b6ea0eda588ac" - } - }, - { - "value": 12.37899270, - "n": 1, - "scriptPubKey": { - "hex": "76a914c353c188620cb33a72d218c0d67fb3f92ad1b6b088ac" - } - } - ] - }, - "347d7c8c1d77f2f835641be27d97900f88be71646bdaa14ffb11b37aaac72f79": { - "hex": "0100000004bc566f299c27644851e70f8646f2ed642985897f488090f5bd5b152d891388a9000000006b483045022100cd5ca45783f836db65a47ba568f97f890155c27ccf0769c1edf231bf6bf49f9b022021d8493fae950bced2c417ce6c4a62aaad495c4d8675e4a4a3e9d86ab44f4b29012102d91223be36388a51cef618ec34c2a1d95f85b6d85d0e07e9e963d84893b5cc4dfefffffff117437f28af1665a002c8351e903de10bd40ab73d54932bbaae28caa6f49a42640000006b483045022100962a7c4b0a96b25fa418f92a69e9f37c5517740d50e996a92724f064bfadcf75022073f1c0475215bef70de392273360655a0b0d4f1f8afd3917614a5dfd1ddd1ca1012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669eafeffffff0dd680cce849762fa7f3f117a1b0e3e7fb6493f2600152143502aa59ad7ca4ed4d0000006b483045022100a6b7befee6468f01e2b3813f05b81241dd5a4c0b04d97a783940c75d97b85ba502206c0dd2fa5cc5c153d359c55f24407c97aec32bf42b2723fc40374188443bd4b2012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669eafeffffffd7e86128b28dcf2046c33f098cfcc2b7f08ea781cc119c0944b2fb23e378135d150000006a47304402204116539acc084920a86bf837ade9d938b517dfa0d346beb969cc97505e6f21520220069a9a33f798a6c1912e29568be2cef12d4db0ea1db751054db5e2311b761854012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669eafeffffff0229b90000000000001976a914da8378d88cd781e0a6f9fdfa6668dd47a718cf6188ac80a35d06000000001976a914707077511db03836716dc01ce47442596264fd8a88acccea0100", - "txid": "347d7c8c1d77f2f835641be27d97900f88be71646bdaa14ffb11b37aaac72f79", - "blocktime": 1547120622, - "time": 1547120622, - "locktime": 125644, - "version": 1, - "vin": [ - { - "txid": "a98813892d155bbdf59080487f89852964edf246860fe7514864279c296f56bc", - "vout": 0, - "sequence": 4294967294, - "scriptSig": { - "hex": "483045022100cd5ca45783f836db65a47ba568f97f890155c27ccf0769c1edf231bf6bf49f9b022021d8493fae950bced2c417ce6c4a62aaad495c4d8675e4a4a3e9d86ab44f4b29012102d91223be36388a51cef618ec34c2a1d95f85b6d85d0e07e9e963d84893b5cc4d" - } - }, - { - "txid": "429af4a6ca28aeba2b93543db70ad40be13d901e35c802a06516af287f4317f1", - "vout": 100, - "sequence": 4294967294, - "scriptSig": { - "hex": "483045022100962a7c4b0a96b25fa418f92a69e9f37c5517740d50e996a92724f064bfadcf75022073f1c0475215bef70de392273360655a0b0d4f1f8afd3917614a5dfd1ddd1ca1012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669ea" - } - }, - { - "txid": "eda47cad59aa023514520160f29364fbe7e3b0a117f1f3a72f7649e8cc80d60d", - "vout": 77, - "sequence": 4294967294, - "scriptSig": { - "hex": "483045022100a6b7befee6468f01e2b3813f05b81241dd5a4c0b04d97a783940c75d97b85ba502206c0dd2fa5cc5c153d359c55f24407c97aec32bf42b2723fc40374188443bd4b2012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669ea" - } - }, - { - "txid": "5d1378e323fbb244099c11cc81a78ef0b7c2fc8c093fc34620cf8db22861e8d7", - "vout": 21, - "sequence": 4294967294, - "scriptSig": { - "hex": "47304402204116539acc084920a86bf837ade9d938b517dfa0d346beb969cc97505e6f21520220069a9a33f798a6c1912e29568be2cef12d4db0ea1db751054db5e2311b761854012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669ea" - } - } - ], - "vout": [ - { - "value": 0.00047401, - "n": 0, - "scriptPubKey": { - "hex": "76a914da8378d88cd781e0a6f9fdfa6668dd47a718cf6188ac" - } - }, - { - "value": 1.06800000, - "n": 1, - "scriptPubKey": { - "hex": "76a914707077511db03836716dc01ce47442596264fd8a88ac" - } - } - ] - } - } -} diff --git a/tests/sync/testdata/zcoin.json b/tests/sync/testdata/zcoin.json deleted file mode 100644 index cbc8872890..0000000000 --- a/tests/sync/testdata/zcoin.json +++ /dev/null @@ -1,285 +0,0 @@ -{ - "connectBlocks": { - "syncRanges": [ - { "lower": 10012, "upper": 10020 }, - { "lower": 121100, "upper": 121150 } - ], - "blocks": { - "10012": { - "height": 10012, - "hash": "270364b0b441f4b5b4c98d073462c0f00e1200fec00410e27f4361e4695a8530", - "noTxs": 2, - "txDetails": [ - { - "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff26021c27062f503253482f043c424258081000cd76000000000d2f6e6f64655374726174756d2f0000000006406a7aee000000001976a9146934fe23ac758cbc21953fadfab01dd3671c01b688ac00c2eb0b000000001976a9147d9ed014fc4e603fca7c2e3f9097fb7d0fb487fc88ac00c2eb0b000000001976a914dcf01f01f5655c10d4fa8149d71cfee36313c02e88ac00c2eb0b000000001976a914ff71b0c9c2a90c6164a50a2fb523eb54a8a6b55088ac00c2eb0b000000001976a9140654dd9b856f2ece1d56cb4ee5043cd9398d962c88ac00c2eb0b000000001976a9140b4bfb256ef4bfa360e3b9e66e53a0bd84d196bc88ac00000000", - "txid": "ec09f614f427ac2553846d4e91bdbac34748502374bb981fc324f27f8c8683f6", - "blocktime": 1480737340, - "time": 1480737340, - "version": 1, - "vin": [ - { - "coinbase": "021c27062f503253482f043c424258081000cd76000000000d2f6e6f64655374726174756d2f", - "sequence": 0 - } - ], - "vout": [ - { - "value": 40.01, - "n": 0, - "scriptPubKey": { - "hex": "76a9146934fe23ac758cbc21953fadfab01dd3671c01b688ac" - } - }, - { - "value": 2.0, - "n": 1, - "scriptPubKey": { - "hex": "76a9147d9ed014fc4e603fca7c2e3f9097fb7d0fb487fc88ac" - } - }, - { - "value": 2.0, - "n": 2, - "scriptPubKey": { - "hex": "76a914dcf01f01f5655c10d4fa8149d71cfee36313c02e88ac" - } - }, - { - "value": 2.0, - "n": 3, - "scriptPubKey": { - "hex": "76a914ff71b0c9c2a90c6164a50a2fb523eb54a8a6b55088ac" - } - }, - { - "value": 2.0, - "n": 4, - "scriptPubKey": { - "hex": "76a9140654dd9b856f2ece1d56cb4ee5043cd9398d962c88ac" - } - }, - { - "value": 2.0, - "n": 5, - "scriptPubKey": { - "hex": "76a9140b4bfb256ef4bfa360e3b9e66e53a0bd84d196bc88ac" - } - } - ] - }, - { - "hex": "0100000001a82d9bb9c02ad9eddfc9d760073b4fc2632b6c939a43d104a8ad08cebee12490000000006b483045022100ecadec884ee8e570bb77704672e223d5cfbaba0aa0957659b8efeabb71392587022076a17e47ac618bcf76c47f6a7fac739dad05f1efda3c61ec5d7cae7021088f370121021a1a3c0f862f7b757930d9654dce951175188eb49f659d9adce95113de5d05f2ffffffff02bc16367e000000001976a9149e694e14a690f487d2a42603dfa1e39e58adcb4688ac01a89721000000001976a914184f6e4e10fb4f1800d32537617528674b6afe0c88ac00000000", - "txid": "c04be7747ef077477aedbec55f1cf6fd51ec2efd58ff978f08884eab3c6fdfbf", - "time": 1480737340, - "blocktime": 1480737340, - "version": 1, - "vin": [ - { - "txid": "9024e1bece08ada804d1439a936c2b63c24f3b0760d7c9dfedd92ac0b99b2da8", - "vout": 0, - "sequence": 4294967295, - "scriptSig": { - "hex": "483045022100ecadec884ee8e570bb77704672e223d5cfbaba0aa0957659b8efeabb71392587022076a17e47ac618bcf76c47f6a7fac739dad05f1efda3c61ec5d7cae7021088f370121021a1a3c0f862f7b757930d9654dce951175188eb49f659d9adce95113de5d05f2" - } - } - ], - "vout": [ - { - "value": 21.1747398, - "n": 0, - "scriptPubKey": { - "hex": "76a9149e694e14a690f487d2a42603dfa1e39e58adcb4688ac" - } - }, - { - "value": 5.63587073, - "n": 1, - "scriptPubKey": { - "hex": "76a914184f6e4e10fb4f1800d32537617528674b6afe0c88ac" - } - } - ] - } - ] - }, - "10013": { - "height": 10013, - "hash": "8be1836104f7adefc0ac8067f56abd1d30725dc05ccb19236be6f538637ec213", - "noTxs": 4, - "txDetails": [ - { - "hex": "0100000001e9f4e2d5180ae0aa5b1ef1fdc496118d6226b688c7986dd9b4215fb4ad59b729010000006a47304402206261d51bf92238e28432307e92fc58af641a15db3a72cfc3a21d5a2ddfdc4d2e022060cd1044cc0a1a2932eaf642f9a4d08b62abb82bde6e7332f65aa343aa204434012102038af35cb691fb64a5af8ae4f3739a3a834363436bb7a4a5d98d9d9eaf46704effffffff02e3c72c00000000001976a914d475cafdcf52e81ee0ed36fa5b1aacebc9cc436f88ac6b638506000000001976a914c8f06a3a16c1210ae30c95111b60c481e20dcc0088ac00000000", - "txid": "01676407d835b8cb9a411136134efcfed3708ba123cb911532b63d9e464eae2e", - "version": 1, - "time": 1480737375, - "blocktime": 1480737375, - "vin": [ - { - "txid": "29b759adb45f21b4d96d98c788b626628d1196c4fdf11e5baae00a18d5e2f4e9", - "vout": 1, - "scriptSig": { - "hex": "47304402206261d51bf92238e28432307e92fc58af641a15db3a72cfc3a21d5a2ddfdc4d2e022060cd1044cc0a1a2932eaf642f9a4d08b62abb82bde6e7332f65aa343aa204434012102038af35cb691fb64a5af8ae4f3739a3a834363436bb7a4a5d98d9d9eaf46704e" - }, - "sequence": 4294967295 - } - ], - "vout": [ - { - "value": 0.02934755, - "n": 0, - "scriptPubKey": { - "hex": "76a914d475cafdcf52e81ee0ed36fa5b1aacebc9cc436f88ac" - } - }, - { - "value": 1.09405035, - "n": 1, - "scriptPubKey": { - "hex": "76a914c8f06a3a16c1210ae30c95111b60c481e20dcc0088ac" - } - } - ] - } - ] - }, - "121100": { - "height": 121100, - "hash": "02bc0d5ae888024d95f1887712def2639c341c8fbb85c25cc3684e8b2b60081f", - "noTxs": 30, - "txDetails": [ - { - "hex": "01000000017ce8aed3eec1d7891141857700287f431090c1f9466e65b4d0f6a751feafa23c000000006b483045022100b7934000466f52a2cbdb63ea099ad30685c82778890f9b06facc09e6e9b3cb5502204a44c5b9c48c2ba4e61b7af467b384fbea8e1efb63296326ca222c97642d61b901210257436124422382febf4003f5bff403aeccab2b6ad901ea1c4d4e08ebb26eadabfeffffff0200105e5f000000001976a914732cd1f18bc5455be4c5f04b120dc4f06ebb2fbc88ac8cd81e03000000001976a914cfcce1c68a8974b1410e971708839fb95c0afcd788ac0bd90100", - "txid": "b71c6ed0b38c9a52fa02c25b79ba2b9f7da599fddae2fdf36dc2fa65bb127699", - "version": 1, - "vin": [ - { - "txid": "3ca2affe51a7f6d0b4656e46f9c19010437f28007785411189d7c1eed3aee87c", - "vout": 0, - "scriptSig": { - "hex": "483045022100b7934000466f52a2cbdb63ea099ad30685c82778890f9b06facc09e6e9b3cb5502204a44c5b9c48c2ba4e61b7af467b384fbea8e1efb63296326ca222c97642d61b901210257436124422382febf4003f5bff403aeccab2b6ad901ea1c4d4e08ebb26eadab" - }, - "sequence": 4294967294 - } - ], - "vout": [ - { - "value": 16.0, - "n": 0, - "scriptPubKey": { - "hex": "76a914732cd1f18bc5455be4c5f04b120dc4f06ebb2fbc88ac" - } - }, - { - "value": 0.52353164, - "n": 1, - "scriptPubKey": { - "hex": "76a914cfcce1c68a8974b1410e971708839fb95c0afcd788ac" - } - } - ], - "time": 1545641453, - "blocktime": 1545641453 - } - ] - } - } - }, - "handleFork": { - "syncRanges": [ - { "lower": 10012, "upper": 10017 }, - { "lower": 121100, "upper": 121104 } - ], - "fakeBlocks": { - "10012": { - "height": 10012, - "hash": "8a647ed7cbc02600775dd6a7fff874a394a9abdfe5d86d9c46aa3d9a4307e010" - }, - "10013": { - "height": 10013, - "hash": "005b810a796c05359264f847f968132981b608138e42655ffd9261e2a2f8e6c8" - }, - "10014": { - "height": 10014, - "hash": "b11ee0e2620bc1a37da725f3cd4a1db9faec2b88ae3e77c9c4d66bbf5106bc44" - }, - "10015": { - "height": 10015, - "hash": "712819a7a0c669c2367660cc246c725de58b68b7f77b803b1964a7c4343a115f" - }, - "10016": { - "height": 10016, - "hash": "69b3ba86607980063eb9a04b9701c8d94206148bae1e3a4324e0fb36ca2e5d11" - }, - "10017": { - "height": 10017, - "hash": "e60984c79e2723a19ebbc37f8d0c10e1e6294f1088c9bed3e532254f68c1a199" - }, - "121100": { - "height": 121100, - "hash": "7eda2cf4cefb5945dbe60fd7e62296ff04fc8a2007f735d574edbbd6e30fb829" - }, - "121101": { - "height": 121101, - "hash": "66d76166f8655a0394e26643c06bea61e0b1d0bc73acca3a53e48d80c7dab4af" - }, - "121102": { - "height": 121102, - "hash": "65e94ebede51ea311784676b0673546e398b882b333be86ed16a100774bed32a" - }, - "121103": { - "height": 121103, - "hash": "2d00b3d85882295717141e9c900d43d3e7b0a7e3ecdeaa05d32ed56d20577a97" - }, - "121104": { - "height": 121104, - "hash": "199220df07b03ddacc3ba0e18a2562c83cb57dff0d12d8953b8233d5a47d7bf3" - } - }, - "realBlocks": { - "10012": { - "height": 10012, - "hash": "270364b0b441f4b5b4c98d073462c0f00e1200fec00410e27f4361e4695a8530" - }, - "10013": { - "height": 10013, - "hash": "8be1836104f7adefc0ac8067f56abd1d30725dc05ccb19236be6f538637ec213" - }, - "10014": { - "height": 10014, - "hash": "def841c7406526043da07f202d67a0b1fe18d10650cbb3661a56722ad814815f" - }, - "10015": { - "height": 10015, - "hash": "4dfab32ae8abb08ecd02b83305606d5d154e57018ff4d12cc744f9cd0b2d47b7" - }, - "10016": { - "height": 10016, - "hash": "e4d49fd46e9d5e7488678356c91e7f8b4d2c69a0dd39e52e107a2987d41e230c" - }, - "10017": { - "height": 10017, - "hash": "713837605fd64f8458cace5b961b28d0f1104665a054a6dde4b3572d520270f5" - }, - "121100": { - "height": 121100, - "hash": "02bc0d5ae888024d95f1887712def2639c341c8fbb85c25cc3684e8b2b60081f" - }, - "121101": { - "height": 121101, - "hash": "aa30be2d62075ee4d147149ef48ad42cd4f6d0fef90c0ec67c117f1b7d7e192f" - }, - "121102": { - "height": 121102, - "hash": "77f49fc80ad9bb5398832332f98f7535e53971fab2dc81f7f3e1fc1dfac8ac7f" - }, - "121103": { - "height": 121103, - "hash": "ed5947e57d68528929d32846a6b7942a5b9db4c98b9eacbd72e8662121bb7971" - }, - "121104": { - "height": 121104, - "hash": "bea29f4df145ea43fd4450aad21ad79388f1fff36b9ab62a1b394440bf47eaf8" - } - } - } -}