diff --git a/CHANGELOG.md b/CHANGELOG.md index d16fa9b..ac4e758 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +#### v1.1.4 +##### 2019-12-04 + +* First-class support for testnet/regtest + #### v1.1.3 ###### 2019-12-02 diff --git a/app.js b/app.js index e495f1b..d321585 100755 --- a/app.js +++ b/app.js @@ -152,6 +152,32 @@ function loadChangelog() { }); } +function loadHistoricalDataForChain(chain) { + global.specialTransactions = {}; + global.specialBlocks = {}; + global.specialAddresses = {}; + + if (config.donations.addresses && config.donations.addresses[coinConfig.ticker]) { + global.specialAddresses[config.donations.addresses[coinConfig.ticker].address] = {type:"donation"}; + } + + if (global.coinConfig.historicalData) { + global.coinConfig.historicalData.forEach(function(item) { + if (item.chain == chain) { + if (item.type == "blockheight") { + global.specialBlocks[item.blockHash] = item; + + } else if (item.type == "tx") { + global.specialTransactions[item.txid] = item; + + } else if (item.type == "address") { + global.specialAddresses[item.address] = {type:"fun", addressInfo:item}; + } + } + }); + } +} + app.onStartup = function() { global.config = config; @@ -209,8 +235,20 @@ app.continueStartup = function() { global.rpcClientNoTimeout = new bitcoinCore(rpcClientNoTimeoutProperties); coreApi.getNetworkInfo().then(function(getnetworkinfo) { - debugLog(`Connected via RPC to node. Basic info: version=${getnetworkinfo.version}, subversion=${getnetworkinfo.subversion}, protocolversion=${getnetworkinfo.protocolversion}, services=${getnetworkinfo.localservices}`); + coreApi.getBlockchainInfo().then(function(getblockchaininfo) { + global.activeBlockchain = getblockchaininfo.chain; + + // localservicenames introduced in 0.19 + var services = getnetworkinfo.localservicesnames ? ("[" + getnetworkinfo.localservicesnames.join(", ") + "]") : getnetworkinfo.localservices; + + debugLog(`RPC Connected: version=${getnetworkinfo.version} (${getnetworkinfo.subversion}), protocolversion=${getnetworkinfo.protocolversion}, chain=${getblockchaininfo.chain}, services=${services}`); + + // load historical/fun items for this chain + loadHistoricalDataForChain(global.activeBlockchain); + }).catch(function(err) { + utils.logError("329u0wsdgewg6ed", err); + }); }).catch(function(err) { utils.logError("32ugegdfsde", err); }); @@ -229,27 +267,6 @@ app.continueStartup = function() { }); } - global.specialTransactions = {}; - global.specialBlocks = {}; - global.specialAddresses = {}; - - if (config.donations.addresses && config.donations.addresses[coinConfig.ticker]) { - global.specialAddresses[config.donations.addresses[coinConfig.ticker].address] = {type:"donation"}; - } - - if (global.coinConfig.historicalData) { - global.coinConfig.historicalData.forEach(function(item) { - if (item.type == "blockheight") { - global.specialBlocks[item.blockHash] = item; - - } else if (item.type == "tx") { - global.specialTransactions[item.txid] = item; - - } else if (item.type == "address") { - global.specialAddresses[item.address] = {type:"fun", addressInfo:item}; - } - }); - } if (config.addressApi) { var supportedAddressApis = addressApi.getSupportedAddressApis(); @@ -280,12 +297,14 @@ app.continueStartup = function() { setInterval(getSourcecodeProjectMetadata, 3600000); } - if (global.exchangeRates == null) { - utils.refreshExchangeRates(); - } + if (global.activeBlockchain == "main") { + if (global.exchangeRates == null) { + utils.refreshExchangeRates(); + } - // refresh exchange rate periodically - setInterval(utils.refreshExchangeRates, 1800000); + // refresh exchange rate periodically + setInterval(utils.refreshExchangeRates, 1800000); + } utils.logMemoryUsage(); setInterval(utils.logMemoryUsage, 5000); diff --git a/app/api/coreApi.js b/app/api/coreApi.js index 5495a88..5ba6531 100644 --- a/app/api/coreApi.js +++ b/app/api/coreApi.js @@ -74,11 +74,11 @@ if (redisCache.active) { function getGenesisBlockHash() { - return coins[config.coin].genesisBlockHash; + return coins[config.coin].genesisBlockHashesByNetwork[global.activeBlockchain]; } function getGenesisCoinbaseTransactionId() { - return coins[config.coin].genesisCoinbaseTransactionId; + return coins[config.coin].genesisCoinbaseTransactionIdsByNetwork[global.activeBlockchain]; } diff --git a/app/api/electrumAddressApi.js b/app/api/electrumAddressApi.js index 69fe331..c6f871c 100644 --- a/app/api/electrumAddressApi.js +++ b/app/api/electrumAddressApi.js @@ -172,7 +172,7 @@ function getAddressTxids(addrScripthash) { if (addrScripthash == coinConfig.genesisCoinbaseOutputAddressScripthash) { for (var i = 0; i < results.length; i++) { - results[i].result.unshift({tx_hash:coinConfig.genesisCoinbaseTransactionId, height:0}); + results[i].result.unshift({tx_hash:coinConfig.genesisCoinbaseTransactionIdsByNetwork[global.activeBlockchain], height:0}); } } @@ -206,7 +206,7 @@ function getAddressBalance(addrScripthash) { if (addrScripthash == coinConfig.genesisCoinbaseOutputAddressScripthash) { for (var i = 0; i < results.length; i++) { - var coinbaseBlockReward = coinConfig.blockRewardFunction(0); + var coinbaseBlockReward = coinConfig.blockRewardFunction(0, global.activeBlockchain); results[i].result.confirmed += (coinbaseBlockReward * coinConfig.baseCurrencyUnit.multiplier); } diff --git a/app/api/rpcApi.js b/app/api/rpcApi.js index 263cec6..cb34a11 100644 --- a/app/api/rpcApi.js +++ b/app/api/rpcApi.js @@ -150,12 +150,18 @@ function getRawTransaction(txid) { debugLog("getRawTransaction: %s", txid); return new Promise(function(resolve, reject) { - if (coins[config.coin].genesisCoinbaseTransactionId && txid == coins[config.coin].genesisCoinbaseTransactionId) { + if (coins[config.coin].genesisCoinbaseTransactionIdsByNetwork[global.activeBlockchain] && txid == coins[config.coin].genesisCoinbaseTransactionIdsByNetwork[global.activeBlockchain]) { // copy the "confirmations" field from genesis block to the genesis-coinbase tx getBlockchainInfo().then(function(blockchainInfoResult) { - var result = coins[config.coin].genesisCoinbaseTransaction; + var result = coins[config.coin].genesisCoinbaseTransactionsByNetwork[global.activeBlockchain]; result.confirmations = blockchainInfoResult.blocks; + // hack: default regtest node returns "0" for number of blocks, despite including a genesis block; + // to display this block without errors, tag it with 1 confirmation + if (global.activeBlockchain == "regtest" && result.confirmations == 0) { + result.confirmations = 1; + } + resolve(result); }).catch(function(err) { diff --git a/app/coins/btc.js b/app/coins/btc.js index 9ce1fcd..7e00c7c 100644 --- a/app/coins/btc.js +++ b/app/coins/btc.js @@ -69,46 +69,121 @@ module.exports = { baseCurrencyUnit:currencyUnits[3], defaultCurrencyUnit:currencyUnits[0], feeSatoshiPerByteBucketMaxima: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 50, 75, 100, 150], - genesisBlockHash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", - genesisCoinbaseTransactionId: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", - genesisCoinbaseTransaction: { - "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d02fd04ffffffff0100f2052a01000000434104f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446aac00000000", - "txid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", - "hash": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", - "size": 204, - "vsize": 204, - "version": 1, - "confirmations":475000, - "vin": [ - { - "coinbase": "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73", - "sequence": 4294967295 - } - ], - "vout": [ - { - "value": 50, - "n": 0, - "scriptPubKey": { - "asm": "04f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446a OP_CHECKSIG", - "hex": "4104f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446aac", - "reqSigs": 1, - "type": "pubkey", - "addresses": [ - "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa" - ] + genesisBlockHashesByNetwork:{ + "main": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + "test": "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", + "regtest": "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206" + }, + genesisCoinbaseTransactionIdsByNetwork: { + "main": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + "test": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + "regtest": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + }, + genesisCoinbaseTransactionsByNetwork:{ + "main": { + "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d02fd04ffffffff0100f2052a01000000434104f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446aac00000000", + "txid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + "hash": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + "size": 204, + "vsize": 204, + "version": 1, + "confirmations":475000, + "vin": [ + { + "coinbase": "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73", + "sequence": 4294967295 } - } - ], - "blockhash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", - "time": 1230988505, - "blocktime": 1230988505 + ], + "vout": [ + { + "value": 50, + "n": 0, + "scriptPubKey": { + "asm": "04f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446a OP_CHECKSIG", + "hex": "4104f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446aac", + "reqSigs": 1, + "type": "pubkey", + "addresses": [ + "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa" + ] + } + } + ], + "blockhash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + "time": 1230988505, + "blocktime": 1230988505 + }, + "test": { + "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + "txid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + "hash": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + "version": 1, + "size": 204, + "vsize": 204, + "weight": 816, + "locktime": 0, + "vin": [ + { + "coinbase": "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73", + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 50.00000000, + "n": 0, + "scriptPubKey": { + "asm": "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG", + "hex": "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac", + "reqSigs": 1, + "type": "pubkey", + "addresses": [ + "mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt" + ] + } + } + ], + "blockhash": "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", + "time": 1296688602, + "blocktime": 1296688602 + }, + "regtest": { + "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", + "txid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + "hash": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + "version": 1, + "size": 204, + "vsize": 204, + "weight": 816, + "locktime": 0, + "vin": [ + { + "coinbase": "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73", + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 50.00000000, + "n": 0, + "scriptPubKey": { + "asm": "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG", + "hex": "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac", + "type": "pubkey" + } + } + ], + "blockhash": "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206", + "time": 1296688602, + "blocktime": 1296688602 + } }, genesisCoinbaseOutputAddressScripthash:"8b01df4e368ea28f8dc0423bcf7a4923e3a12d307c875e47a0cfbf90b5c39161", historicalData: [ { type: "blockheight", date: "2009-01-03", + chain: "main", blockHeight: 0, blockHash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", summary: "The Bitcoin Genesis Block.", @@ -118,6 +193,7 @@ module.exports = { { type: "tx", date: "2009-01-03", + chain: "main", txid: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", summary: "The coinbase transaction of the Genesis Block.", alertBodyHtml: "This transaction doesn't really exist! This is the coinbase transaction of the Bitcoin Genesis Block. For more background about this special-case transaction, you can read this brief discussion among some of the Bitcoin developers.", @@ -126,6 +202,7 @@ module.exports = { { type: "tx", date: "2009-10-12", + chain: "main", txid: "7dff938918f07619abd38e4510890396b1cef4fbeca154fb7aafba8843295ea2", summary: "First bitcoin traded for fiat currency.", alertBodyHtml: "In this first-known BTC-to-fiat transaction, 5,050 BTC were exchanged for 5.02 USD, at an effective exchange rate of ~0.001 USD/BTC.", @@ -134,6 +211,7 @@ module.exports = { { type: "blockheight", date: "2017-08-24", + chain: "main", blockHeight: 481824, blockHash: "0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893", summary: "First SegWit block.", @@ -142,6 +220,7 @@ module.exports = { { type: "tx", date: "2017-08-24", + chain: "main", txid: "8f907925d2ebe48765103e6845C06f1f2bb77c6adc1cc002865865eb5cfd5c1c", summary: "First SegWit transaction.", referenceUrl: "https://twitter.com/KHS9NE/status/900553902923362304" @@ -149,6 +228,7 @@ module.exports = { { type: "tx", date: "2014-06-16", + chain: "main", txid: "143a3d7e7599557f9d63e7f224f34d33e9251b2c23c38f95631b3a54de53f024", summary: "Star Wars: A New Hope", referenceUrl: "" @@ -156,6 +236,7 @@ module.exports = { { type: "tx", date: "2010-05-22", + chain: "main", txid: "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", summary: "The 'Bitcoin Pizza' transaction.", alertBodyHtml: "This is the famous 'Bitcoin Pizza' transaction.", @@ -164,6 +245,7 @@ module.exports = { { type: "tx", date: "2011-05-18", + chain: "main", txid: "5d80a29be1609db91658b401f85921a86ab4755969729b65257651bb9fd2c10d", summary: "Destroyed bitcoin.", referenceUrl: "https://bitcointalk.org/index.php?topic=7253.msg184414#msg184414", @@ -172,6 +254,7 @@ module.exports = { { type: "blockheight", date: "2009-01-12", + chain: "main", blockHeight: 170, blockHash: "00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee", summary: "First block containing a (non-coinbase) transaction.", @@ -181,6 +264,7 @@ module.exports = { { type: "blockheight", date: "2017-08-25", + chain: "main", blockHeight: 481947, blockHash: "00000000000000000139cb443e16442fcd07a4a0e0788dd045ee3cf268982016", summary: "First block mined that was greater than 1MB.", @@ -189,6 +273,7 @@ module.exports = { { type: "blockheight", date: "2018-01-20", + chain: "main", blockHeight: 505225, blockHash: "0000000000000000001bbb529c64ddf55edec8f4ebc0a0ccf1d3bb21c278bfa7", summary: "First block mined that was greater than 2MB.", @@ -197,6 +282,7 @@ module.exports = { { type: "tx", date: "2017-12-30", + chain: "main", txid: "9bf8853b3a823bbfa1e54017ae11a9e1f4d08a854dcce9f24e08114f2c921182", summary: "Block reward lost", alertBodyHtml: "This coinbase transaction completely fails to collect the block's mining reward. 12.5 BTC were lost.", @@ -205,6 +291,7 @@ module.exports = { { type:"address", date:"2011-12-03", + chain: "main", address:"1JryTePceSiWVpoNBU8SbwiT7J4ghzijzW", summary:"Brainwallet address for 'Satoshi Nakamoto'", referenceUrl:"https://twitter.com/MrHodl/status/1041448002005741568", @@ -213,6 +300,7 @@ module.exports = { { type: "tx", date: "2010-11-14", + chain: "main", txid: "e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468", summary: "Duplicated coinbase transaction #1", referenceUrl: "https://bitcoin.stackexchange.com/questions/38994/will-there-be-21-million-bitcoins-eventually/38998#38998", @@ -221,11 +309,56 @@ module.exports = { { type: "tx", date: "2010-11-14", + chain: "main", txid: "d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599", summary: "Duplicated coinbase transaction #2", referenceUrl: "https://bitcoin.stackexchange.com/questions/38994/will-there-be-21-million-bitcoins-eventually/38998#38998", alertBodyHtml: "This is one of 2 'duplicate coinbase' transactions. An early bitcoin bug (fixed by BIP30) allowed identical coinbase transactions - a newer duplicate would overwrite older copies. This transaction was the coinbase transaction for Block #91,812 and, ~3 hours later, Block #91,842. The 50 BTC claimed as the coinbase for block 91,812 were also overwritten and lost." - } + }, + + + // testnet + { + type: "blockheight", + date: "2011-02-02", + chain: "test", + blockHeight: 0, + blockHash: "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", + summary: "The Bitcoin (regtest) Genesis Block.", + alertBodyHtml: "This is the first block in the Bitcoin blockchain, known as the 'Genesis Block'. You can read more about the genesis block.", + referenceUrl: "https://en.bitcoin.it/wiki/Genesis_block" + }, + { + type: "tx", + date: "2011-02-02", + chain: "test", + txid: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + summary: "The coinbase transaction of the Genesis Block.", + alertBodyHtml: "This transaction doesn't really exist! This is the coinbase transaction of the Bitcoin Genesis Block. For more background about this special-case transaction, you can read this brief discussion among some of the Bitcoin developers.", + referenceUrl: "https://github.com/bitcoin/bitcoin/issues/3303" + }, + + + // regtest + { + type: "blockheight", + date: "2011-02-02", + chain: "regtest", + blockHeight: 0, + blockHash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206", + summary: "The Bitcoin (regtest) Genesis Block.", + alertBodyHtml: "This is the first block in the Bitcoin blockchain, known as the 'Genesis Block'. You can read more about the genesis block.", + referenceUrl: "https://en.bitcoin.it/wiki/Genesis_block" + }, + { + type: "tx", + date: "2011-02-02", + chain: "regtest", + txid: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + summary: "The coinbase transaction of the Genesis Block.", + alertBodyHtml: "This transaction doesn't really exist! This is the coinbase transaction of the Bitcoin Genesis Block. For more background about this special-case transaction, you can read this brief discussion among some of the Bitcoin developers.", + referenceUrl: "https://github.com/bitcoin/bitcoin/issues/3303" + }, ], exchangeRateData:{ jsonUrl:"https://api.coindesk.com/v1/bpi/currentprice.json", @@ -249,14 +382,15 @@ module.exports = { return null; } }, - blockRewardFunction:function(blockHeight) { + blockRewardFunction:function(blockHeight, chain) { var eras = [ new Decimal8(50) ]; for (var i = 1; i < 34; i++) { var previous = eras[i - 1]; eras.push(new Decimal8(previous).dividedBy(2)); } - var index = Math.floor(blockHeight / 210000); + var halvingBlockInterval = (chain == "regtest" ? 150 : 210000); + var index = Math.floor(blockHeight / halvingBlockInterval); return eras[index]; } diff --git a/app/utils.js b/app/utils.js index e507955..3dcc0ef 100644 --- a/app/utils.js +++ b/app/utils.js @@ -284,7 +284,7 @@ function getTxTotalInputOutputValues(tx, txInputs, blockHeight) { try { for (var i = 0; i < tx.vin.length; i++) { if (tx.vin[i].coinbase) { - totalInputValue = totalInputValue.plus(new Decimal(coinConfig.blockRewardFunction(blockHeight))); + totalInputValue = totalInputValue.plus(new Decimal(coinConfig.blockRewardFunction(blockHeight, global.activeBlockchain))); } else { var txInput = txInputs[i]; @@ -317,7 +317,7 @@ function getBlockTotalFeesFromCoinbaseTxAndBlockHeight(coinbaseTx, blockHeight) return 0; } - var blockReward = coinConfig.blockRewardFunction(blockHeight); + var blockReward = coinConfig.blockRewardFunction(blockHeight, global.activeBlockchain); var totalOutput = new Decimal(0); for (var i = 0; i < coinbaseTx.vout.length; i++) { diff --git a/routes/baseActionsRouter.js b/routes/baseActionsRouter.js index ac069c9..64f118b 100644 --- a/routes/baseActionsRouter.js +++ b/routes/baseActionsRouter.js @@ -74,6 +74,10 @@ router.get("/", function(req, res, next) { for (var i = 0; i < 10; i++) { blockHeights.push(getblockchaininfo.blocks - i); } + } else if (global.activeBlockchain == "regtest") { + // hack: default regtest node returns getblockchaininfo.blocks=0, despite having a genesis block + // hack this to display the genesis block + blockHeights.push(0); } if (getblockchaininfo.chain !== 'regtest') { diff --git a/views/fun.pug b/views/fun.pug index e194fa1..74b2aac 100644 --- a/views/fun.pug +++ b/views/fun.pug @@ -19,34 +19,35 @@ block content th(class="data-header") Reference tbody each item, index in coinConfig.historicalData - tr - td(class="data-cell") #{item.date} + if (item.chain == global.activeBlockchain) + tr + td(class="data-cell") #{item.date} - td(class="data-cell") #{item.summary} - - td(class="data-cell monospace") - if (item.type == "tx") - a(href=("/tx/" + item.txid), title=item.txid, data-toggle="tooltip") Tx #{item.txid.substring(0, 23)}... - else if (item.type == "block") - a(href=("/block/" + item.blockHash), title="Block #{item.blockHash}", data-toggle="tooltip") Block #{item.blockHash.substring(0, 20)}... - else if (item.type == "blockheight") - a(href=("/block/" + item.blockHash)) Block ##{item.blockHeight} - else if (item.type == "address") - a(href=("/address/" + item.address), title=item.address, data-toggle="tooltip") Address #{item.address.substring(0, 18)}... - else if (item.type == "link") - a(href=item.url) #{item.url.substring(0, 20)}... + td(class="data-cell") #{item.summary} + + td(class="data-cell monospace") + if (item.type == "tx") + a(href=("/tx/" + item.txid), title=item.txid, data-toggle="tooltip") Tx #{item.txid.substring(0, 23)}... + else if (item.type == "block") + a(href=("/block/" + item.blockHash), title="Block #{item.blockHash}", data-toggle="tooltip") Block #{item.blockHash.substring(0, 20)}... + else if (item.type == "blockheight") + a(href=("/block/" + item.blockHash)) Block ##{item.blockHeight} + else if (item.type == "address") + a(href=("/address/" + item.address), title=item.address, data-toggle="tooltip") Address #{item.address.substring(0, 18)}... + else if (item.type == "link") + a(href=item.url) #{item.url.substring(0, 20)}... - td(class="data-cell") - if (item.referenceUrl && item.referenceUrl.trim().length > 0) - - var matches = item.referenceUrl.match(/^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)/i); + td(class="data-cell") + if (item.referenceUrl && item.referenceUrl.trim().length > 0) + - var matches = item.referenceUrl.match(/^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)/i); - - var domain = null; - - var domain = matches && matches[1]; + - var domain = null; + - var domain = matches && matches[1]; - if (domain) - a(href=item.referenceUrl, rel="nofollow") #{domain} - i(class="fas fa-external-link-alt") + if (domain) + a(href=item.referenceUrl, rel="nofollow") #{domain} + i(class="fas fa-external-link-alt") + else + a(href=item.referenceUrl, rel="nofollow") Reference else - a(href=item.referenceUrl, rel="nofollow") Reference - else - span - \ No newline at end of file + span - \ No newline at end of file diff --git a/views/includes/block-content.pug b/views/includes/block-content.pug index 765f227..ba97ab6 100644 --- a/views/includes/block-content.pug +++ b/views/includes/block-content.pug @@ -73,7 +73,7 @@ div(class="tab-content") - var currencyValue = new Decimal(result.getblock.totalFees).dividedBy(result.getblock.tx.length); include ./value-display.pug - - var blockRewardMax = coinConfig.blockRewardFunction(result.getblock.height); + - var blockRewardMax = coinConfig.blockRewardFunction(result.getblock.height, global.activeBlockchain); - var coinbaseTxTotalOutputValue = new Decimal(0); each vout in result.getblock.coinbaseTx.vout - coinbaseTxTotalOutputValue = coinbaseTxTotalOutputValue.plus(new Decimal(vout.value)); diff --git a/views/includes/transaction-io-details.pug b/views/includes/transaction-io-details.pug index b14a145..0dc9eee 100644 --- a/views/includes/transaction-io-details.pug +++ b/views/includes/transaction-io-details.pug @@ -61,7 +61,7 @@ div(class="row monospace") div(class="tx-io-value") if (txVin.coinbase) - - var currencyValue = coinConfig.blockRewardFunction(blockHeight); + - var currencyValue = coinConfig.blockRewardFunction(blockHeight, global.activeBlockchain); include ./value-display.pug else if (vout && vout.value) diff --git a/views/layout.pug b/views/layout.pug index 5acb4de..4379043 100644 --- a/views/layout.pug +++ b/views/layout.pug @@ -44,6 +44,12 @@ html(lang="en") a(href="/about", class="nav-link") span About + if (global.activeBlockchain != "main") + - var chainName = global.activeBlockchain == "test" ? "testnet" : global.activeBlockchain + + li.nav-item + a.nav-link.text-warning(title=`Current node's chain: ${global.activeBlockchain}` data-toggle="tooltip") [#{chainName}] + if (config.siteTools) li(class="nav-item dropdown") a(class="nav-link dropdown-toggle", href="javascript:void(0)", role="button", data-toggle="dropdown", aria-haspopup="true", aria-expanded="false") diff --git a/views/peers.pug b/views/peers.pug index 3244ae4..8dbc291 100644 --- a/views/peers.pug +++ b/views/peers.pug @@ -34,7 +34,7 @@ block content div(id="tab-summary", class="tab-pane active", role="tabpanel") - if (peerIpSummary.ips) + if (peerIpSummary && peerIpSummary.ips) div(id="map", class="mb-4") div(class="card mb-4 shadow-sm") @@ -93,7 +93,7 @@ block content th(class="data-header") Address th(class="data-header") Services - if (peerIpSummary.ips) + if (peerIpSummary && peerIpSummary.ips) th(class="data-header") Location th(class="data-header") Last Send / Receive @@ -161,7 +161,7 @@ block endOfBody $(".data-table").DataTable(); }); - if (peerIpSummary.ips) + if (peerIpSummary && peerIpSummary.ips) script. var mymap = L.map('map').setView([21.505, -0.09], 3); diff --git a/views/transaction.pug b/views/transaction.pug index ae1a5f7..95b3e0d 100644 --- a/views/transaction.pug +++ b/views/transaction.pug @@ -27,7 +27,7 @@ block content - var totalInputValue = new Decimal(0); if (result.getrawtransaction.vin[0].coinbase) - - totalInputValue = totalInputValue.plus(new Decimal(coinConfig.blockRewardFunction(result.getblock.height))); + - totalInputValue = totalInputValue.plus(new Decimal(coinConfig.blockRewardFunction(result.getblock.height, global.activeBlockchain))); each txInput, txInputIndex in result.txInputs if (txInput) - var vout = txInput.vout[result.getrawtransaction.vin[txInputIndex].vout]; @@ -168,7 +168,7 @@ block content - var currencyValue = new Decimal(totalOutputValue).minus(totalInputValue); include includes/value-display.pug - - var blockRewardMax = coinConfig.blockRewardFunction(result.getblock.height); + - var blockRewardMax = coinConfig.blockRewardFunction(result.getblock.height, global.activeBlockchain); if (parseFloat(totalOutputValue) < parseFloat(blockRewardMax)) div(class="row") div(class="summary-table-label")