diff --git a/apps/ecash-herald/config.js b/apps/ecash-herald/config.js --- a/apps/ecash-herald/config.js +++ b/apps/ecash-herald/config.js @@ -22,53 +22,4 @@ parse_mode: 'HTML', disable_web_page_preview: true, }, - knownMiners: [ - { - coinbaseScript: '566961425443', - miner: 'ViaBTC', - }, - { - coinbaseScript: '4d696e696e672d4475746368', - miner: 'Mining-Dutch', - }, - ], - opReturn: { - opReturnPrefix: '6a', - opReturnAppPrefixLength: '04', - opPushDataOne: '4c', - appPrefixes: { - '00746162': 'Cashtab Msg', - '2e786563': 'Alias', - }, - memo: { - 'prefix': '026d', - 'app': 'memo', - '01': 'Set name', - '02': 'Post memo', - '03': 'Reply to memo', - '04': 'Like / tip memo', - '05': 'Set profile text', - '06': 'Follow user', - '07': 'Unfollow user', - '0a': 'Set profile picture', - '0b': 'Repost memo', - '0c': 'Post topic message', - '0d': 'Topic follow', - '0e': 'Topic unfollow', - '10': 'Create poll', - '13': 'Add poll option', - '14': 'Poll vote', - '16': 'Mute user', - '17': 'Unmute user', - '24': 'Send money', - '30': 'Sell tokens Spec', - '31': 'Token buy offer Spec', - '32': 'Attach token sale signature Spec', - '35': 'Pin token post', - '20': 'Link request', - '21': 'Link accept', - '22': 'Link revoke', - '26': 'Set address alias', - }, - }, }; diff --git a/apps/ecash-herald/constants/miners.js b/apps/ecash-herald/constants/miners.js new file mode 100644 --- /dev/null +++ b/apps/ecash-herald/constants/miners.js @@ -0,0 +1,18 @@ +// Copyright (c) 2023 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +'use strict'; +/** + * miners.js + * Constants related to parsing for known miners of ecash blocks + */ +module.exports = [ + { + coinbaseScript: '566961425443', + miner: 'ViaBTC', + }, + { + coinbaseScript: '4d696e696e672d4475746368', + miner: 'Mining-Dutch', + }, +]; diff --git a/apps/ecash-herald/constants/op_return.js b/apps/ecash-herald/constants/op_return.js new file mode 100644 --- /dev/null +++ b/apps/ecash-herald/constants/op_return.js @@ -0,0 +1,48 @@ +// Copyright (c) 2023 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +'use strict'; +/** + * op_return.js + * Constants related to OP_RETURN script + * https://en.bitcoin.it/wiki/Script + */ +module.exports = { + opReturnPrefix: '6a', + opReturnAppPrefixLength: '04', + opPushDataOne: '4c', + appPrefixes: { + '00746162': 'Cashtab Msg', + '2e786563': 'Alias', + }, + memo: { + 'prefix': '026d', + 'app': 'memo', + '01': 'Set name', + '02': 'Post memo', + '03': 'Reply to memo', + '04': 'Like / tip memo', + '05': 'Set profile text', + '06': 'Follow user', + '07': 'Unfollow user', + '0a': 'Set profile picture', + '0b': 'Repost memo', + '0c': 'Post topic message', + '0d': 'Topic follow', + '0e': 'Topic unfollow', + '10': 'Create poll', + '13': 'Add poll option', + '14': 'Poll vote', + '16': 'Mute user', + '17': 'Unmute user', + '24': 'Send money', + '30': 'Sell tokens Spec', + '31': 'Token buy offer Spec', + '32': 'Attach token sale signature Spec', + '35': 'Pin token post', + '20': 'Link request', + '21': 'Link accept', + '22': 'Link revoke', + '26': 'Set address alias', + }, +}; diff --git a/apps/ecash-herald/src/parse.js b/apps/ecash-herald/src/parse.js --- a/apps/ecash-herald/src/parse.js +++ b/apps/ecash-herald/src/parse.js @@ -4,6 +4,8 @@ 'use strict'; const config = require('../config'); +const opReturn = require('../constants/op_return'); +const knownMiners = require('../constants/miners'); const cashaddr = require('ecashaddrjs'); const BigNumber = require('bignumber.js'); const { @@ -39,7 +41,6 @@ return { hash, height, miner, numTxs, parsedTxs, tokenIds }; }, getMinerFromCoinbase: function (coinbaseHexString) { - const knownMiners = config.knownMiners; let miner = 'unknown'; // Iterate over known miners to find a match for (let i = 0; i < knownMiners.length; i += 1) { @@ -159,9 +160,7 @@ } // Don't parse OP_RETURN values of etoken txs, this info is available from chronik if ( - thisOutput.outputScript.startsWith( - config.opReturn.opReturnPrefix, - ) && + thisOutput.outputScript.startsWith(opReturn.opReturnPrefix) && !isTokenTx ) { opReturnInfo = module.exports.parseOpReturn( @@ -228,16 +227,14 @@ let msg; // Determine if this is an OP_RETURN field - const isOpReturn = - outputScript.slice(0, 2) === config.opReturn.opReturnPrefix; + const isOpReturn = outputScript.slice(0, 2) === opReturn.opReturnPrefix; if (!isOpReturn) { return false; } // Determine if this is a memo tx // Memo txs have a shorter prefix and require special processing - const isMemoTx = - outputScript.slice(2, 6) === config.opReturn.memo.prefix; + const isMemoTx = outputScript.slice(2, 6) === opReturn.memo.prefix; if (isMemoTx) { // memo txs require special processing // Send the unprocessed remainder of the string to a specialized function @@ -247,13 +244,12 @@ // Parse for app prefix // See https://github.com/Bitcoin-ABC/bitcoin-abc/blob/master/web/standards/op_return-prefix-guideline.md const hasAppPrefix = - outputScript.slice(2, 4) === - config.opReturn.opReturnAppPrefixLength; + outputScript.slice(2, 4) === opReturn.opReturnAppPrefixLength; if (hasAppPrefix) { const appPrefix = outputScript.slice(4, 12); - if (Object.keys(config.opReturn.appPrefixes).includes(appPrefix)) { - app = config.opReturn.appPrefixes[appPrefix]; + if (Object.keys(opReturn.appPrefixes).includes(appPrefix)) { + app = opReturn.appPrefixes[appPrefix]; } else { app = 'unknown app'; } @@ -300,7 +296,7 @@ // Check first byte for the message length or 4c + message length let byteValue = hexStr.slice(0, 2); let msgByteSize = 0; - if (byteValue === config.opReturn.opPushDataOne) { + if (byteValue === opReturn.opPushDataOne) { // If this byte is 4c, then the next byte is the message byte size. // Retrieve the message byte size and convert from hex to decimal msgByteSize = parseInt(hexStr.substring(2, 4), 16); @@ -333,7 +329,7 @@ // Remove the memo prefix, already processed memoHexStr = memoHexStr.slice(6); // At the beginning of this function, we have already popped off '0d6d' - let app = config.opReturn.memo.app; + let app = opReturn.memo.app; let msg = ''; for (let i = 0; memoHexStr !== 0; i++) { // Get the memo action code @@ -345,14 +341,14 @@ case '01' || '02' || '05' || '0a' || '0c' || '0d' || '0e': // Action codes where the entire string may be parsed to utf8 msg += `${ - config.opReturn.memo[actionCode] + opReturn.memo[actionCode] }|${module.exports.hexOpReturnToUtf8(memoHexStr)}`; break; default: // parse the rest of the string like a normal op_return utf8 string msg += `${ - Object.keys(config.opReturn.memo).includes(actionCode) - ? config.opReturn.memo[actionCode] + Object.keys(opReturn.memo).includes(actionCode) + ? opReturn.memo[actionCode] : '' }|${module.exports.hexOpReturnToUtf8(memoHexStr)}`; } @@ -525,7 +521,7 @@ // Throw out OP_RETURN outputs for txs parsed as XEC send txs xecReceivingAddressOutputs.forEach((value, key, map) => { - if (key.startsWith(config.opReturn.opReturnPrefix)) { + if (key.startsWith(opReturn.opReturnPrefix)) { map.delete(key); } }); diff --git a/apps/ecash-herald/test/mocks/memo.js b/apps/ecash-herald/test/mocks/memo.js --- a/apps/ecash-herald/test/mocks/memo.js +++ b/apps/ecash-herald/test/mocks/memo.js @@ -3,29 +3,29 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. 'use strict'; -const config = require('../../config'); +const opReturn = require('../../constants/op_return'); module.exports = [ // Set name { txid: '753e29e81cdea12dc5fa30ca89049ca7d538d4062c4bb1b19ecf2a209a3ac8d9', - action: config.opReturn.memo['01'], + action: opReturn.memo['01'], outputScript: '6a026d0106746573742032', - parsed: `${config.opReturn.memo['01']}|test 2`, + parsed: `${opReturn.memo['01']}|test 2`, }, // Post memo { txid: 'c7e91099923a28cf86685c9683c74c8c029c8965a5039f84ad79886b42720f9b', - action: config.opReturn.memo['02'], + action: opReturn.memo['02'], outputScript: '6a026d02374c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c6974', - parsed: `${config.opReturn.memo['02']}|Lorem ipsum dolor sit amet, consectetur adipiscing elit`, + parsed: `${opReturn.memo['02']}|Lorem ipsum dolor sit amet, consectetur adipiscing elit`, }, // Reply to memo, parsing not yet fully supported { txid: '28f3ec1f134dc8ea2e37a0645774fa2aa19e0bc2871b6edcc7e99cd86d77b1b6', - action: config.opReturn.memo['03'], + action: opReturn.memo['03'], outputScript: '6a026d0320965689bc694d816ab0745b501c0e9dc8dbe7994a185fe37a37b808dc6b05750a4c8546726f6d20776861742049276d20676174686572696e672c206974207365656d73207468617420746865206d656469612077656e742066726f6d207175657374696f6e696e6720617574686f7269747920746f20646f696e672074686569722062696464696e67206173206120636f6c6c656374697665204e504320686976656d696e6421', - parsed: `${config.opReturn.memo['03']}|�V��iM�j�t[P\u001c\u000e����J\u0018_�z7�\b�k\u0005u\n|From what I'm gathering, it seems that the media went from questioning authority to doing their bidding as a collective NPC hivemind!`, + parsed: `${opReturn.memo['03']}|�V��iM�j�t[P\u001c\u000e����J\u0018_�z7�\b�k\u0005u\n|From what I'm gathering, it seems that the media went from questioning authority to doing their bidding as a collective NPC hivemind!`, }, ]; diff --git a/apps/ecash-herald/test/parseTests.js b/apps/ecash-herald/test/parseTests.js --- a/apps/ecash-herald/test/parseTests.js +++ b/apps/ecash-herald/test/parseTests.js @@ -4,7 +4,7 @@ 'use strict'; const assert = require('assert'); -const config = require('../config'); +const opReturn = require('../constants/op_return'); const unrevivedBlocks = require('./mocks/blocks'); const { jsonReviver } = require('../src/utils'); const blocks = JSON.parse(JSON.stringify(unrevivedBlocks), jsonReviver); @@ -36,7 +36,7 @@ }); it(`parseMemoOutputScript correctly parses all tested memo actions in memo.js`, function () { memoOutputScripts.map(memoTestObj => { - const app = config.opReturn.memo.app; + const app = opReturn.memo.app; const { outputScript, parsed } = memoTestObj; assert.deepEqual(parseMemoOutputScript(outputScript), { app,