Browse Source

first-class support for testnet/regtest

* display chain/network in header if not mainnet
* indicate active chain/network in startup log
* specify which chain/network "fun" items apply to and only show them for that chain
* don't display exchange rates for testnet/regtest
* use block interval of 150 for regtest halving
* regtest hacks: since getblockchaininfo.blocks=0 on a default regtest node despite the genesis block existing, hack in a couple of places in order to display the genesis block
* fix /peers page to not throw error with no connections
master
Dan Janosik 5 years ago
parent
commit
44f3631fb1
No known key found for this signature in database GPG Key ID: C6F8CE9FFDB2CED2
  1. 5
      CHANGELOG.md
  2. 73
      app.js
  3. 4
      app/api/coreApi.js
  4. 4
      app/api/electrumAddressApi.js
  5. 10
      app/api/rpcApi.js
  6. 206
      app/coins/btc.js
  7. 4
      app/utils.js
  8. 4
      routes/baseActionsRouter.js
  9. 53
      views/fun.pug
  10. 2
      views/includes/block-content.pug
  11. 2
      views/includes/transaction-io-details.pug
  12. 6
      views/layout.pug
  13. 6
      views/peers.pug
  14. 4
      views/transaction.pug

5
CHANGELOG.md

@ -1,3 +1,8 @@
#### v1.1.4
##### 2019-12-04
* First-class support for testnet/regtest
#### v1.1.3
###### 2019-12-02

73
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);

4
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];
}

4
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);
}

10
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) {

206
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 <a href='/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'>Bitcoin Genesis Block</a>. For more background about this special-case transaction, you can read <a href='https://github.com/bitcoin/bitcoin/issues/3303'>this brief discussion</a> among some of the <a href='https://bitcoin.org'>Bitcoin</a> 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 <a href='https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki'>BIP30</a>) allowed identical coinbase transactions - a newer duplicate would overwrite older copies. This transaction was the coinbase transaction for <a href='/block-height/91812'>Block #91,812</a> and, ~3 hours later, <a href='/block-height/91842'>Block #91,842</a>. 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 <a href='https://en.bitcoin.it/wiki/Genesis_block'>the genesis block</a>.",
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 <a href='/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'>Bitcoin Genesis Block</a>. For more background about this special-case transaction, you can read <a href='https://github.com/bitcoin/bitcoin/issues/3303'>this brief discussion</a> among some of the <a href='https://bitcoin.org'>Bitcoin</a> 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 <a href='https://en.bitcoin.it/wiki/Genesis_block'>the genesis block</a>.",
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 <a href='/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'>Bitcoin Genesis Block</a>. For more background about this special-case transaction, you can read <a href='https://github.com/bitcoin/bitcoin/issues/3303'>this brief discussion</a> among some of the <a href='https://bitcoin.org'>Bitcoin</a> 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];
}

4
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++) {

4
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') {

53
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 -
span -

2
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));

2
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)

6
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")

6
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);

4
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")

Loading…
Cancel
Save