├── .eslintignore ├── .prettierignore ├── docs └── images │ └── demo.png ├── .gitignore ├── examples ├── subscription │ ├── kth-inside.png │ ├── package.json │ ├── index.html │ ├── index.js │ ├── index_just_one_sub.js │ └── kth-inside.svg ├── encoding.js ├── addressGenerator.js ├── blockchainSync.js ├── subscribe.js └── subscribe_multiple.js ├── .prettierrc ├── src ├── result.d.ts ├── result.js ├── config │ ├── network.d.ts │ ├── nodeSettings.js │ ├── network.js │ ├── databaseSettings.js │ ├── networkSettings.js │ ├── blockchainSettings.js │ ├── settings.js │ └── settings.d.ts ├── numerics.d.ts ├── primitives.d.ts ├── common.js ├── chain │ ├── script.d.ts │ ├── outputPoint.d.ts │ ├── output.d.ts │ ├── input.d.ts │ ├── header.d.ts │ ├── block.d.ts │ ├── transaction.d.ts │ ├── outputPoint.js │ ├── blockList.js │ ├── inputList.js │ ├── outputList.js │ ├── transactionList.js │ ├── chain.d.ts │ ├── genericList.js │ ├── script.js │ ├── output.js │ ├── input.js │ ├── header.js │ ├── transaction.js │ └── block.js ├── utils │ ├── lazySequence.d.ts │ └── lazySequence.js ├── primitives.js ├── node.d.ts ├── numerics.js ├── encoding.d.ts ├── wallet │ ├── wallet.d.ts │ ├── paymentAddress.d.ts │ ├── wallet.js │ └── paymentAddress.js ├── kth.d.ts ├── kth.js ├── encoding.js ├── node.js └── errors.js ├── test ├── chain │ ├── outputPoint.test.js │ ├── script.test.js │ ├── output.test.js │ ├── header.test.js │ ├── input.test.js │ ├── genesis.txt │ ├── transaction.test.js │ └── block.test.js ├── config │ ├── nodeSettings.test.js │ ├── databaseSettings.test.js │ ├── networkSettings.test.js │ ├── blockchainSettings.test.js │ └── settings.test.js ├── encoding.test.js └── wallet │ ├── paymentAddress.test.js │ └── wallet.test.js ├── .eslintrc.js ├── package.json ├── .github └── workflows │ └── npm-publish.yml └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /docs/images/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k-nuth/js-api/HEAD/docs/images/demo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | blockchain/ 3 | debug.log 4 | error.log 5 | .DS_Store 6 | hosts.cache 7 | *.mdb 8 | -------------------------------------------------------------------------------- /examples/subscription/kth-inside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k-nuth/js-api/HEAD/examples/subscription/kth-inside.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "tabWidth": 4, 4 | "useTabs": false, 5 | "printWidth": 120, 6 | "singleQuote": true, 7 | "trailingComma": "none" 8 | } 9 | -------------------------------------------------------------------------------- /src/result.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | export declare class Result { 6 | constructor(obj: Type, ok: boolean); 7 | } 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/subscription/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "subscription", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "test" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@knuth/bch": "^1.19.0", 13 | "express": "^4.18.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/result.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | class Result { 6 | constructor(obj, ok) { 7 | this.obj = obj; 8 | this.ok = ok; 9 | } 10 | } 11 | 12 | exports.Result = Result; 13 | -------------------------------------------------------------------------------- /src/config/network.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | export enum Network { 6 | mainnet = 0, 7 | testnet = 1, 8 | regtest = 2, 9 | testnet4 = 3, 10 | scalenet = 4, 11 | chipnet = 5, 12 | } 13 | -------------------------------------------------------------------------------- /src/numerics.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | export declare function toSatoshisFactor(): number; 6 | 7 | export declare function toSatoshis(amount: number): number; 8 | 9 | export declare function fromSatoshis(amount: number): number; -------------------------------------------------------------------------------- /src/primitives.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | export enum StartModules { 6 | all = 0, 7 | justChain = 1, 8 | justP2P = 2 9 | } 10 | 11 | export enum DbMode { 12 | pruned = 0, 13 | normal = 1, 14 | fullIndexed = 2 15 | } -------------------------------------------------------------------------------- /test/chain/outputPoint.test.js: -------------------------------------------------------------------------------- 1 | const outputPoint = require('../../src/chain/outputPoint'); 2 | const enc = require('../../src/encoding'); 3 | 4 | test('use constructor', () => { 5 | const op = new outputPoint.OutputPoint(enc.Hash.nullHash(), 0xffffffff); 6 | expect(op.index).toBe(0xffffffff); 7 | expect(enc.Hash.bytesToStr(op.hash)).toBe('0000000000000000000000000000000000000000000000000000000000000000'); 8 | }); 9 | -------------------------------------------------------------------------------- /src/config/nodeSettings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | 7 | const getDefault = (network) => { 8 | return kth.config_node_settings_default(network); 9 | }; 10 | 11 | exports.getDefault = getDefault; 12 | -------------------------------------------------------------------------------- /examples/encoding.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | /* eslint-disable */ 6 | 7 | const enc = require('../src/encoding'); 8 | 9 | const hash = enc.Hash.strToBytes('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f') 10 | console.log(hash); 11 | -------------------------------------------------------------------------------- /src/config/network.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const Network = Object.freeze({ 6 | mainnet: 0, 7 | testnet: 1, 8 | regtest: 2, 9 | testnet4: 3, 10 | scalenet: 4, 11 | chipnet: 5, 12 | }); 13 | 14 | exports.Network = Network; 15 | -------------------------------------------------------------------------------- /src/common.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | // Copyright (c) 2016-2024 Knuth Project developers. 4 | // Distributed under the MIT software license, see the accompanying 5 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 6 | 7 | const kth = require('@knuth/bch-native') 8 | 9 | const common = { 10 | toData: function(obj) { 11 | const native = obj.toNative(); 12 | return obj; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/config/databaseSettings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | 7 | const getDefault = (network) => { 8 | return kth.config_database_settings_default(network); 9 | }; 10 | 11 | exports.getDefault = getDefault; 12 | -------------------------------------------------------------------------------- /src/config/networkSettings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | 7 | const getDefault = (network) => { 8 | return kth.config_network_settings_default(network); 9 | }; 10 | 11 | exports.getDefault = getDefault; 12 | -------------------------------------------------------------------------------- /src/config/blockchainSettings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | 7 | const getDefault = (network) => { 8 | return kth.config_blockchain_settings_default(network); 9 | }; 10 | 11 | exports.getDefault = getDefault; 12 | -------------------------------------------------------------------------------- /src/chain/script.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | export declare class Script { 6 | constructor(enconded: Uint8Array); 7 | 8 | toNative(prefix: boolean): any; 9 | 10 | rawData(): Uint8Array; 11 | } 12 | 13 | export declare function fromNative(native: any, prefix: boolean, destroy: boolean): any; -------------------------------------------------------------------------------- /src/utils/lazySequence.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | declare class LazySequence { 6 | constructor(generatorFunc: () => Generator); 7 | take(count: number): LazySequence; 8 | map(transformFunc: (item: T) => U): LazySequence; 9 | toArray(): T[]; 10 | } 11 | 12 | export = LazySequence; 13 | -------------------------------------------------------------------------------- /src/chain/outputPoint.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | export declare class OutputPoint { 6 | constructor(hash: Uint8Array, index: number); 7 | 8 | toNative(): any; 9 | } 10 | 11 | export declare function fromNative(native: any, destroy: boolean): OutputPoint; 12 | 13 | export declare function destruct(native: any): void; -------------------------------------------------------------------------------- /src/primitives.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const StartModules = Object.freeze({ 6 | all: 0, 7 | justChain: 1, 8 | justP2P: 2 9 | }); 10 | 11 | const DbMode = Object.freeze({ 12 | pruned: 0, 13 | normal: 1, 14 | fullIndexed: 2 15 | }); 16 | 17 | exports.StartModules = StartModules; 18 | exports.DbMode = DbMode; 19 | -------------------------------------------------------------------------------- /test/config/nodeSettings.test.js: -------------------------------------------------------------------------------- 1 | const nodeSettings = require('../../src/config/nodeSettings'); 2 | const network = require('../../src/config/network'); 3 | 4 | test('read default settings', () => { 5 | const settings = nodeSettings.getDefault(network.Network.mainnet); 6 | expect(settings.syncPeers).toBe(0); 7 | expect(settings.syncTimeoutSeconds).toBe(5); 8 | expect(settings.blockLatencySeconds).toBe(60); 9 | expect(settings.refreshTransactions).toBe(true); 10 | expect(settings.compactBlocksHighBandwidth).toBe(true); 11 | }); 12 | -------------------------------------------------------------------------------- /src/config/settings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | 7 | const getDefault = (network) => { 8 | return kth.config_settings_default(network); 9 | }; 10 | 11 | const getFromFile = (file) => { 12 | return kth.config_settings_get_from_file(file); 13 | }; 14 | 15 | exports.getDefault = getDefault; 16 | exports.getFromFile = getFromFile; 17 | -------------------------------------------------------------------------------- /src/node.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { Chain } from './chain/chain'; 6 | import { Settings } from './config/settings'; 7 | import { StartModules } from './primitives'; 8 | 9 | export declare class Node { 10 | constructor(settings: Settings, stdoutEnabled: boolean); 11 | 12 | get chain(): undefined | Chain; 13 | 14 | close(): void; 15 | 16 | launch(mods: StartModules): Promise; 17 | } 18 | -------------------------------------------------------------------------------- /src/numerics.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | function toSatoshisFactor() { 6 | return 100000000; 7 | } 8 | 9 | function toSatoshis(amount) { 10 | return amount * toSatoshisFactor(); 11 | } 12 | 13 | function fromSatoshis(satoshis) { 14 | return satoshis / toSatoshisFactor(); 15 | } 16 | 17 | exports.toSatoshisFactor = toSatoshisFactor; 18 | exports.toSatoshis = toSatoshis; 19 | exports.fromSatoshis = fromSatoshis; 20 | -------------------------------------------------------------------------------- /src/encoding.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | export declare function bytesToHexStr(uint8arr: Uint8Array): string; 6 | 7 | export declare function hexStrToBytes(str: string): Uint8Array; 8 | 9 | export declare function reverseStr(s: string): string; 10 | 11 | export declare function fix(arr: number[]): Uint8Array; 12 | 13 | export namespace Hash { 14 | export function bytesToStr(arr: Uint8Array): string; 15 | export function strToBytes(s: string): Uint8Array; 16 | export function nullHash(): Uint8Array; 17 | } -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | jest: true 6 | }, 7 | extends: ['eslint:recommended', 'plugin:prettier/recommended'], 8 | parserOptions: { 9 | ecmaVersion: 12 10 | }, 11 | rules: { 12 | 'prettier/prettier': [ 13 | 'error', 14 | {}, 15 | { 16 | usePrettierrc: true 17 | } 18 | ], 19 | 'linebreak-style': 0, 20 | 'no-console': 0, 21 | 'no-use-before-define': 0, 22 | 'no-bitwise': 0, 23 | 'no-plusplus': 0, 24 | 'max-len': 0, 25 | 'max-classes-per-file': 0, 26 | indent: ['error', 4] 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /test/config/databaseSettings.test.js: -------------------------------------------------------------------------------- 1 | const databaseSettings = require('../../src/config/databaseSettings'); 2 | const network = require('../../src/config/network'); 3 | const primitives = require('../../src/primitives'); 4 | 5 | test('read default settings', () => { 6 | const settings = databaseSettings.getDefault(network.Network.mainnet); 7 | expect(settings.directory).toBe('blockchain'); 8 | expect(settings.dbMode).toBe(primitives.DbMode.normal); 9 | expect(settings.reorgPoolLimit).toBe(100); 10 | // expect(settings.dbMaxSize).toBe(600 * 1024 * 1024 * 1024); 11 | expect(settings.dbMaxSize).toBe(200 * 1024 * 1024 * 1024); 12 | expect(settings.safeMode).toBe(true); 13 | expect(settings.cacheCapacity).toBe(0); 14 | }); 15 | -------------------------------------------------------------------------------- /src/chain/output.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { Script } from './script'; 6 | import { Result } from '../result'; 7 | 8 | export declare class Output { 9 | constructor(value: number, script: Script); 10 | 11 | toNative(): any; 12 | 13 | rawData(wire: boolean): Uint8Array; 14 | } 15 | 16 | export declare function fromNative(native: any, destroy: boolean): Output; 17 | 18 | export declare function fromData(data: Uint8Array): Result; 19 | 20 | export declare function toData(obj: Output, wire: boolean): Uint8Array; 21 | 22 | export declare function destruct(native: any): void; -------------------------------------------------------------------------------- /src/chain/input.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { Script } from './script'; 6 | import { OutputPoint } from './outputPoint'; 7 | import { Result } from '../result'; 8 | 9 | export declare class Input { 10 | constructor(previousOutpoint: OutputPoint, script: Script, sequence: number); 11 | 12 | toNative(): any; 13 | 14 | rawData(wire: boolean): Uint8Array; 15 | } 16 | 17 | export declare function fromNative(native: any, destroy: boolean): Input; 18 | 19 | export declare function fromData(data: Uint8Array): Result; 20 | 21 | export declare function toData(obj: Input, wire: boolean): Uint8Array; 22 | 23 | export declare function destruct(native: any): void; -------------------------------------------------------------------------------- /src/chain/header.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { Result } from '../result'; 6 | 7 | export declare class Header { 8 | constructor(version: number, previousBlockHash: Uint8Array, merkle: Uint8Array, timestamp: number , bits: number, nonce: number); 9 | 10 | toNative(): any; 11 | 12 | get hash(): Uint8Array; 13 | 14 | rawData(version: number): Uint8Array; 15 | } 16 | 17 | export declare function fromNative(native: any, destroy: boolean): Header; 18 | 19 | export declare function fromData(version: number, data: Uint8Array): Result
; 20 | 21 | export declare function toData(obj: Header, version: number): Uint8Array; 22 | 23 | export declare function hash(obj: Header): Uint8Array; 24 | 25 | export declare function destruct(native: any): void; -------------------------------------------------------------------------------- /src/chain/block.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { Result } from '../result'; 6 | import { Header } from './header'; 7 | import { Transaction } from './transaction' 8 | 9 | export declare class Block { 10 | constructor(header: Header, transactions: Transaction[]); 11 | 12 | toNative(): any; 13 | 14 | get hash(): Uint8Array; 15 | 16 | rawData(wire: boolean): Uint8Array; 17 | } 18 | 19 | export declare function fromNative(native: any, destroy: boolean): Block; 20 | 21 | export declare function fromData(version: number, data: Uint8Array): Result; 22 | 23 | export declare function toData(obj: Block, wire: boolean): Uint8Array; 24 | 25 | export declare function hash(obj: Block): Uint8Array; 26 | 27 | export declare function destruct(native: any): void; -------------------------------------------------------------------------------- /src/chain/transaction.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { Output } from './output'; 6 | import { Input } from './input'; 7 | import { Result } from '../result'; 8 | 9 | export declare class Transaction { 10 | constructor(version: number, locktime: number, inputs: Input[], outputs: Output[]); 11 | 12 | toNative(): any; 13 | 14 | get hash(): Uint8Array; 15 | 16 | rawData(wire: boolean): Uint8Array; 17 | } 18 | 19 | export declare function fromNative(native: any, destroy: boolean): Transaction; 20 | 21 | export declare function fromData(version: number, data: Uint8Array): Result; 22 | 23 | export declare function toData(obj: Transaction, wire: boolean): Uint8Array; 24 | 25 | export declare function hash(obj: Transaction): Uint8Array; 26 | 27 | export declare function destruct(native: any): void; 28 | -------------------------------------------------------------------------------- /src/wallet/wallet.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { LazySequence } from '../utils/lazySequence'; 6 | import { PaymentAddress } from './paymentAddress'; 7 | 8 | export declare class Wallet { 9 | constructor(mnemonic: string[], derivationPath: string, network?: string); 10 | 11 | readonly rootKey: string; 12 | readonly extendedPrivateKey: string; 13 | readonly extendedPublicKey: string; 14 | 15 | getAddress(index: number): PaymentAddress; 16 | getAddresses(count?: number): PaymentAddress[]; 17 | generateAddresses(): LazySequence; 18 | 19 | deriveAccount(derivationPath: string): Wallet; 20 | 21 | //TODO: static generate(): Wallet; 22 | //TODO: static isValidMnemonic(mnemonic: string[]): boolean; 23 | //TODO: mnemonic(): string[]; 24 | //TODO: toPublic(): Wallet; 25 | } 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/chain/outputPoint.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | 7 | class OutputPoint { 8 | constructor(hash, index) { 9 | this.hash = hash; 10 | this.index = index; 11 | } 12 | 13 | toNative() { 14 | const native = kth.chain_output_point_construct_from_hash_index(this.hash, this.index); 15 | return native; 16 | } 17 | } 18 | 19 | const fromNative = (native, destroy = false) => { 20 | const obj = new OutputPoint(kth.chain_output_point_get_hash(native), kth.chain_output_point_get_index(native)); 21 | if (destroy) { 22 | destruct(native); 23 | } 24 | return obj; 25 | }; 26 | 27 | const destruct = (native) => { 28 | kth.chain_output_point_destruct(native); 29 | }; 30 | 31 | exports.fromNative = fromNative; 32 | exports.destruct = destruct; 33 | exports.OutputPoint = OutputPoint; 34 | -------------------------------------------------------------------------------- /src/chain/blockList.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const block = require('./block'); 7 | const genericList = require('./genericList'); 8 | 9 | const methods = { 10 | count: (native) => kth.chain_block_list_count(native), 11 | nth: (native, i) => kth.chain_block_list_nth(native, i), 12 | fromNative: (elementNative) => block.fromNative(elementNative), 13 | constructDefault: () => kth.chain_block_list_construct_default(), 14 | pushBack: (native, elementNative) => kth.chain_block_list_push_back(native, elementNative), 15 | destruct: (native) => kth.chain_block_list_destruct(native) 16 | }; 17 | 18 | const instance = genericList.template(methods); 19 | exports.fromNative = (native, destroy = false) => instance.fromNative(native, destroy); 20 | exports.toNative = (arr) => instance.toNative(arr); 21 | exports.destruct = (native) => instance.destruct(native); 22 | -------------------------------------------------------------------------------- /src/chain/inputList.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const input = require('./input'); 7 | const genericList = require('./genericList'); 8 | 9 | const methods = { 10 | count: (native) => kth.chain_input_list_count(native), 11 | nth: (native, i) => kth.chain_input_list_nth(native, i), 12 | fromNative: (elementNative) => input.fromNative(elementNative), 13 | constructDefault: () => kth.chain_input_list_construct_default(), 14 | pushBack: (native, elementNative) => kth.chain_input_list_push_back(native, elementNative), 15 | destruct: (native) => kth.chain_input_list_destruct(native) 16 | }; 17 | 18 | const instance = genericList.template(methods); 19 | exports.fromNative = (native, destroy = false) => instance.fromNative(native, destroy); 20 | exports.toNative = (arr) => instance.toNative(arr); 21 | exports.destruct = (native) => instance.destruct(native); 22 | -------------------------------------------------------------------------------- /src/chain/outputList.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const output = require('./output'); 7 | const genericList = require('./genericList'); 8 | 9 | const methods = { 10 | count: (native) => kth.chain_output_list_count(native), 11 | nth: (native, i) => kth.chain_output_list_nth(native, i), 12 | fromNative: (elementNative) => output.fromNative(elementNative), 13 | constructDefault: () => kth.chain_output_list_construct_default(), 14 | pushBack: (native, elementNative) => kth.chain_output_list_push_back(native, elementNative), 15 | destruct: (native) => kth.chain_output_list_destruct(native) 16 | }; 17 | 18 | const instance = genericList.template(methods); 19 | exports.fromNative = (native, destroy = false) => instance.fromNative(native, destroy); 20 | exports.toNative = (arr) => instance.toNative(arr); 21 | exports.destruct = (native) => instance.destruct(native); 22 | -------------------------------------------------------------------------------- /src/utils/lazySequence.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | class LazySequence { 6 | constructor(generatorFunc) { 7 | this.generatorFunc = generatorFunc; 8 | } 9 | 10 | *[Symbol.iterator]() { 11 | yield* this.generatorFunc(); 12 | } 13 | 14 | take(count) { 15 | const self = this; 16 | return new LazySequence(function*() { 17 | let index = 0; 18 | for (let item of self) { 19 | if (index++ < count) yield item; 20 | else break; 21 | } 22 | }); 23 | } 24 | 25 | map(transformFunc) { 26 | const self = this; 27 | return new LazySequence(function*() { 28 | for (let item of self) { 29 | yield transformFunc(item); 30 | } 31 | }); 32 | } 33 | 34 | toArray() { 35 | return [...this]; 36 | } 37 | } 38 | 39 | exports.LazySequence = LazySequence; -------------------------------------------------------------------------------- /src/chain/transactionList.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const transaction = require('./transaction'); 7 | const genericList = require('./genericList'); 8 | 9 | const methods = { 10 | count: (native) => kth.chain_transaction_list_count(native), 11 | nth: (native, i) => kth.chain_transaction_list_nth(native, i), 12 | fromNative: (elementNative) => transaction.fromNative(elementNative), 13 | constructDefault: () => kth.chain_transaction_list_construct_default(), 14 | pushBack: (native, elementNative) => kth.chain_transaction_list_push_back(native, elementNative), 15 | destruct: (native) => kth.chain_transaction_list_destruct(native) 16 | }; 17 | 18 | const instance = genericList.template(methods); 19 | exports.fromNative = (native, destroy = false) => instance.fromNative(native, destroy); 20 | exports.toNative = (arr) => instance.toNative(arr); 21 | exports.destruct = (native) => instance.destruct(native); 22 | -------------------------------------------------------------------------------- /src/kth.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import * as node from './node'; 6 | 7 | import * as enc from './encoding'; 8 | import { StartModules as startModules } from './primitives'; 9 | import { DbMode as dbMode } from './primitives'; 10 | 11 | import * as block from './chain/block'; 12 | import * as header from './chain/header'; 13 | import * as input from './chain/input'; 14 | import * as output from './chain/output'; 15 | import * as outputPoint from './chain/outputPoint'; 16 | import * as script from './chain/script'; 17 | import * as transaction from './chain/transaction'; 18 | 19 | import * as settings from './config/settings'; 20 | import { Network as network } from './config/network'; 21 | 22 | export { 23 | node, 24 | enc, 25 | startModules, 26 | dbMode, 27 | 28 | //Chain 29 | block, 30 | header, 31 | input, 32 | output, 33 | outputPoint, 34 | script, 35 | transaction, 36 | 37 | //Config 38 | settings, 39 | network 40 | } -------------------------------------------------------------------------------- /src/wallet/paymentAddress.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { Result } from '../result'; 6 | 7 | export declare class PaymentAddress { 8 | constructor(addressStr: string); 9 | 10 | toNative(): any; 11 | 12 | get hash(): Uint8Array; 13 | 14 | get version(): number; 15 | 16 | encoded(): string; 17 | 18 | encodedCashAddr(): string; 19 | 20 | encodedLegacy(): string; 21 | } 22 | 23 | export declare function fromNative(native: any, destroy: boolean): PaymentAddress; 24 | 25 | export declare function fromData(addressStr: string): Result; 26 | 27 | export declare function isValid(addressStr: string): boolean; 28 | 29 | export declare function encodedLegacy(obj: PaymentAddress): string; 30 | 31 | export declare function encodedCashAddr(obj: PaymentAddress): string; 32 | 33 | export declare function hash(obj: PaymentAddress): Uint8Array; 34 | 35 | export declare function version(obj: PaymentAddress): number; 36 | 37 | export declare function destruct(native: any): void; 38 | -------------------------------------------------------------------------------- /examples/addressGenerator.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | /* eslint-disable */ 6 | 7 | // const kth = require("@knuth/bch") 8 | // const kth = require('../src/kth'); 9 | const { Wallet } = require('../src/wallet/wallet'); 10 | const { PaymentAddress } = require('../src/wallet/paymentAddress'); 11 | 12 | async function main() { 13 | 14 | const TEST_MNEMONIC = [ 15 | 'car', 'slab', 'tail', 'dirt', 'wife', 'custom', 'front', 16 | 'shield', 'diet', 'pear', 'skull', 'vapor', 'gorilla', 'token', 'yard' 17 | ]; 18 | 19 | const TEST_DERIVATION_PATH = "m/44'/145'/0'/0"; 20 | const TEST_NETWORK = 'MAINNET'; 21 | 22 | const wallet = new Wallet(TEST_MNEMONIC, TEST_DERIVATION_PATH, TEST_NETWORK); 23 | const addresses = wallet.getAddresses(20000); 24 | 25 | const addrStr = addresses.map(a => a.encoded()); 26 | console.log(addrStr); 27 | 28 | wallet.printPerformance(); 29 | 30 | } 31 | 32 | (async () => { 33 | try { 34 | await main(); 35 | } catch (e) { 36 | console.log(e); 37 | } 38 | })(); 39 | -------------------------------------------------------------------------------- /src/chain/chain.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { Block } from "./block"; 6 | import { Header } from "./header"; 7 | import { Transaction } from "./transaction"; 8 | 9 | export declare class Chain { 10 | constructor(native : any); 11 | 12 | getLastHeight() : Promise<[number, number]>; 13 | getBlockHeight(hash : Uint8Array) : Promise<[number, number]>; 14 | 15 | getBlockHeaderByHeight(height : number) : Promise<[number, Header, number]>; 16 | getBlockHeaderByHash(hash : Uint8Array) : Promise<[number, Header, number]>; 17 | 18 | getBlockByHeight(height : number) : Promise<[number, Block, number]>; 19 | getBlockByHash(hash : Uint8Array) : Promise<[number, Block, number]>; 20 | 21 | getTransaction(hash : Uint8Array, requireConfirmed : boolean) : Promise<[number, Transaction, number, number]>; 22 | getTransactionPosition(hash : Uint8Array, requireConfirmed : boolean) : Promise<[number, number, number]>; 23 | 24 | // Organizers 25 | organizeBlock(block : Block) : Promise; 26 | organizeTransaction(transaction : Transaction) : Promise; 27 | } 28 | -------------------------------------------------------------------------------- /src/chain/genericList.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const template = (methods) => { 6 | return { 7 | fromNative: (native, destroy = false) => { 8 | let arr = []; 9 | const n = methods.count(native); 10 | for (let i = 0; i < n; ++i) { 11 | const elementNative = methods.nth(native, i); 12 | const element = methods.fromNative(elementNative); 13 | arr.push(element); 14 | } 15 | 16 | if (destroy) { 17 | methods.destruct(native); 18 | } 19 | return arr; 20 | }, 21 | 22 | toNative: (arr) => { 23 | const native = methods.constructDefault(); 24 | 25 | for (let i = 0; i < arr.length; ++i) { 26 | const element = arr[i]; 27 | const elementNative = element.toNative(); 28 | methods.pushBack(native, elementNative); 29 | } 30 | return native; 31 | }, 32 | 33 | destruct: (native) => { 34 | methods.destruct(native); 35 | } 36 | }; 37 | }; 38 | 39 | exports.template = template; 40 | -------------------------------------------------------------------------------- /src/kth.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const node = require('./node'); 6 | 7 | const enc = require('./encoding'); 8 | const primitives = require('./primitives'); 9 | 10 | const block = require('./chain/block'); 11 | const header = require('./chain/header'); 12 | const input = require('./chain/input'); 13 | const output = require('./chain/output'); 14 | const outputPoint = require('./chain/outputPoint'); 15 | const script = require('./chain/script'); 16 | const transaction = require('./chain/transaction'); 17 | 18 | const paymentAddress = require('./wallet/paymentAddress'); 19 | const wallet = require('./wallet/wallet'); 20 | 21 | const settings = require('./config/settings'); 22 | const sett_network = require('./config/network'); 23 | 24 | const err = require('../src/errors'); 25 | 26 | module.exports = { 27 | node, 28 | enc, 29 | errors: err.errors, 30 | 31 | startModules: primitives.StartModules, 32 | dbMode: primitives.DbMode, 33 | 34 | //Chain 35 | block, 36 | header, 37 | input, 38 | output, 39 | outputPoint, 40 | script, 41 | transaction, 42 | 43 | //Wallet 44 | paymentAddress, 45 | wallet, 46 | 47 | //Config 48 | settings, 49 | network: sett_network.Network 50 | }; 51 | -------------------------------------------------------------------------------- /test/chain/script.test.js: -------------------------------------------------------------------------------- 1 | const script = require('../../src/chain/script'); 2 | const enc = require('../../src/encoding'); 3 | 4 | test('construct using fromData() prefix false', () => { 5 | const scriptStr = 6 | '0130323066643366303435313438356531306633383837363437356630643265396130393739343332353534313766653139316438623963623230653430643863333030326431373463336539306366323433393231383761313037623634373337633937333135633932393264653431373731636565613062323563633534353732653302ae'; 7 | const scriptBytes = enc.hexStrToBytes(scriptStr); 8 | const result = script.fromData(scriptBytes, false); 9 | expect(result.ok).toBe(true); 10 | const s = result.obj; 11 | const roundtrip = s.rawData(false); 12 | expect(enc.fix(roundtrip)).toEqual(scriptBytes); 13 | }); 14 | 15 | test('construct using fromData() prefix true', () => { 16 | const scriptStr = 17 | '3045022100ff1fc58dbd608e5e05846a8e6b45a46ad49878aef6879ad1a7cf4c5a7f853683022074a6a10f6053ab3cddc5620d169c7374cd42c1416c51b9744db2c8d9febfb84d01'; 18 | const scriptBytes = enc.hexStrToBytes(scriptStr); 19 | const result = script.fromData(scriptBytes, true); 20 | expect(result.ok).toBe(true); 21 | }); 22 | 23 | test('construct using fromData() roundtrips', () => { 24 | const scriptStr = '76a91406ccef231c2db72526df9338894ccf9355e8f12188ac'; 25 | const scriptBytes = enc.hexStrToBytes(scriptStr); 26 | const result = script.fromData(scriptBytes, false); 27 | expect(result.ok).toBe(true); 28 | const s = result.obj; 29 | const roundtrip = s.rawData(false); 30 | expect(enc.fix(roundtrip)).toEqual(scriptBytes); 31 | }); 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@knuth/bch", 3 | "version": "2.6.0", 4 | "description": "Bitcoin Cash development platform for Javascript and Typescript applications", 5 | "main": "src/kth.js", 6 | "scripts": { 7 | "test": "jest --runInBand --verbose", 8 | "lint": "eslint **/*.js", 9 | "lint:fix": "npm run lint -- --fix", 10 | "lint:github-action": "node ./node_modules/eslint/bin/eslint . --ignore-path .gitignore" 11 | }, 12 | "husky": { 13 | "hooks": { 14 | "pre-commit": "lint-staged" 15 | } 16 | }, 17 | "lint-staged": { 18 | "**/*.js": [ 19 | "eslint --fix" 20 | ] 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/k-nuth/js-api.git" 25 | }, 26 | "keywords": [ 27 | "bitcoin", 28 | "cash", 29 | "bch", 30 | "money", 31 | "knuth", 32 | "kth" 33 | ], 34 | "author": "Knuth Project developers (https://kth.cash)", 35 | "license": "MIT", 36 | "bugs": { 37 | "url": "https://github.com/k-nuth/kth/issues" 38 | }, 39 | "homepage": "https://github.com/k-nuth/js-api#readme", 40 | "dependencies": { 41 | "bluebird": "^3.7.2", 42 | "@knuth/bch-native": "^1.7.0", 43 | "memoizee": "^0.4.14" 44 | }, 45 | "devDependencies": { 46 | "eslint": "^7.20.0", 47 | "eslint-config-prettier": "^8.0.0", 48 | "eslint-plugin-import": "^2.22.1", 49 | "eslint-plugin-prettier": "^3.3.1", 50 | "husky": "^8.0.3", 51 | "jest": "^29.7.0", 52 | "lint-staged": "^13.2.1", 53 | "prettier": "^2.2.1" 54 | }, 55 | "directories": { 56 | "example": "examples", 57 | "test": "test" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/chain/script.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const memoize = require('memoizee'); 7 | const result = require('../result'); 8 | 9 | class Script { 10 | constructor(encoded) { 11 | this.encoded = encoded; 12 | } 13 | 14 | toNative(prefix) { 15 | const native = kth.chain_script_construct(this.encoded, prefix); 16 | return native; 17 | } 18 | 19 | rawData() { 20 | const res = memoizedToData(this); 21 | return res; 22 | } 23 | } 24 | 25 | const fromNative = (native, prefix, destroy = false) => { 26 | const obj = new Script(kth.chain_script_to_data(native, prefix)); 27 | if (destroy) { 28 | destruct(native); 29 | } 30 | return obj; 31 | }; 32 | 33 | const fromData = (encoded, prefix) => { 34 | const native = kth.chain_script_construct(encoded, prefix); 35 | const valid = kth.chain_script_is_valid(native); 36 | if (!valid) { 37 | destruct(native); 38 | return new result.Result(undefined, false); 39 | } 40 | const obj = fromNative(native, prefix); 41 | destruct(native); 42 | return new result.Result(obj, true); 43 | }; 44 | 45 | const toData = (obj) => { 46 | const res = obj.encoded; 47 | return res; 48 | }; 49 | 50 | const memoizedToData = memoize(toData); 51 | 52 | const destruct = (native) => { 53 | kth.chain_script_destruct(native); 54 | }; 55 | 56 | exports.fromNative = fromNative; 57 | exports.fromData = fromData; 58 | exports.destruct = destruct; 59 | exports.Script = Script; 60 | -------------------------------------------------------------------------------- /examples/blockchainSync.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | /* eslint-disable */ 6 | 7 | const kth = require("@knuth/bch") 8 | // const kth = require('../src/kth'); 9 | 10 | let running_ = false; 11 | 12 | async function main() { 13 | process.on('SIGINT', shutdown); 14 | const config = kth.settings.getDefault(kth.network.mainnet); 15 | console.log(`Default config: ${JSON.stringify(config)}`); 16 | const node = new kth.node.Node(config, true); 17 | console.log("Knuth node has been created."); 18 | await node.launch(kth.startModules.all); 19 | console.log("Knuth node has been launched."); 20 | running_ = true; 21 | 22 | const [_, height] = await node.chain.getLastHeight(); 23 | console.log(`Current height in local copy: ${height}`); 24 | 25 | if (await comeBackAfterTheBCHHardFork(node)) { 26 | console.log("Bitcoin Cash has been created!"); 27 | } 28 | 29 | node.close(); 30 | console.log("Good bye!"); 31 | } 32 | 33 | async function comeBackAfterTheBCHHardFork(node) { 34 | const hfHeight = 478559; 35 | while (running_) { 36 | const [_, height] = await node.chain.getLastHeight(); 37 | if (height >= hfHeight) return true; 38 | await sleep(10000); 39 | } 40 | return false; 41 | } 42 | 43 | function shutdown() { 44 | console.log('Graceful shutdown ...'); 45 | running_ = false; 46 | } 47 | 48 | function sleep(ms) { 49 | return new Promise((r) => setTimeout(r, ms)); 50 | } 51 | 52 | (async () => { 53 | try { 54 | await main(); 55 | } catch (e) { 56 | console.log(e); 57 | } 58 | })(); 59 | -------------------------------------------------------------------------------- /src/encoding.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | function bytesToHexStr(uint8arr) { 6 | if (!uint8arr) { 7 | return ''; 8 | } 9 | 10 | let hexStr = ''; 11 | for (let i = 0; i < uint8arr.length; i++) { 12 | let hex = (uint8arr[i] & 0xff).toString(16); 13 | hex = hex.length === 1 ? `0${hex}` : hex; 14 | hexStr += hex; 15 | } 16 | 17 | return hexStr.toLowerCase(); 18 | } 19 | 20 | function hexStrToBytes(str) { 21 | if (!str) { 22 | return new Uint8Array(); 23 | } 24 | 25 | const a = []; 26 | for (let i = 0, len = str.length; i < len; i += 2) { 27 | a.push(parseInt(str.substr(i, 2), 16)); 28 | } 29 | 30 | return new Uint8Array(a); 31 | } 32 | 33 | function reverseStr(s) { 34 | return s.split('').reverse().join(''); 35 | } 36 | 37 | function fix(arr) { 38 | return new Uint8Array(arr); 39 | } 40 | 41 | class Hash { 42 | static bytesToStr(arr) { 43 | const reversed = [...arr]; 44 | reversed.reverse(); 45 | return bytesToHexStr(reversed); 46 | } 47 | 48 | static strToBytes(s) { 49 | return hexStrToBytes(s).reverse(); 50 | } 51 | 52 | // eslint --fix: Parsing error: Unexpected token = 53 | // static nullHash = Hash.strToBytes('0000000000000000000000000000000000000000000000000000000000000000'); 54 | 55 | static nullHash() { 56 | return Hash.strToBytes('0000000000000000000000000000000000000000000000000000000000000000'); 57 | } 58 | } 59 | 60 | exports.bytesToHexStr = bytesToHexStr; 61 | exports.hexStrToBytes = hexStrToBytes; 62 | exports.reverseStr = reverseStr; 63 | exports.fix = fix; 64 | exports.Hash = Hash; 65 | -------------------------------------------------------------------------------- /examples/subscription/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Block Height Counter 7 | 8 | 9 | 10 | 11 | 32 | 33 | 34 |
35 | Bitcoin 36 |
37 |
Latest Synchronized Block Height
38 |

The current block height is: 0

39 |
40 |
41 | 42 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/chain/output.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const memoize = require('memoizee'); 7 | const script = require('./script'); 8 | const result = require('../result'); 9 | 10 | class Output { 11 | constructor(value, script) { 12 | this.value = value; 13 | this.script = script; 14 | } 15 | 16 | toNative() { 17 | const native = kth.chain_output_construct(this.value, this.script.toNative(false)); 18 | return native; 19 | } 20 | 21 | rawData(wire = true) { 22 | const res = memoizedToData(this, wire); 23 | return res; 24 | } 25 | } 26 | 27 | const fromNative = (native, destroy = false) => { 28 | const obj = new Output(kth.chain_output_value(native), script.fromNative(kth.chain_output_script(native), false)); 29 | if (destroy) { 30 | destruct(native); 31 | } 32 | return obj; 33 | }; 34 | 35 | const fromData = (data) => { 36 | const native = kth.chain_output_factory_from_data(data); 37 | const valid = kth.chain_output_is_valid(native); 38 | if (!valid) { 39 | destruct(native); 40 | return new result.Result(undefined, false); 41 | } 42 | const obj = fromNative(native); 43 | destruct(native); 44 | return new result.Result(obj, true); 45 | }; 46 | 47 | const toData = (obj, wire) => { 48 | const native = obj.toNative(); 49 | const res = kth.chain_output_to_data(native, wire); 50 | destruct(native); 51 | return res; 52 | }; 53 | 54 | const memoizedToData = memoize(toData); 55 | 56 | const destruct = (native) => { 57 | kth.chain_output_destruct(native); 58 | }; 59 | 60 | exports.fromNative = fromNative; 61 | exports.fromData = fromData; 62 | exports.destruct = destruct; 63 | exports.Output = Output; 64 | -------------------------------------------------------------------------------- /src/chain/input.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const memoize = require('memoizee'); 7 | const script = require('./script'); 8 | const outputPoint = require('./outputPoint'); 9 | const result = require('../result'); 10 | 11 | class Input { 12 | constructor(previousOutpoint, script, sequence) { 13 | this.previousOutpoint = previousOutpoint; 14 | this.script = script; 15 | this.sequence = sequence; 16 | } 17 | 18 | toNative() { 19 | const native = kth.chain_input_construct( 20 | this.previousOutpoint.toNative(), 21 | this.script.toNative(false), 22 | this.sequence 23 | ); 24 | return native; 25 | } 26 | 27 | rawData(wire = true) { 28 | const res = memoizedToData(this, wire); 29 | return res; 30 | } 31 | } 32 | 33 | const fromNative = (native, destroy = false) => { 34 | const obj = new Input( 35 | outputPoint.fromNative(kth.chain_input_previous_output(native)), 36 | script.fromNative(kth.chain_input_script(native), false), 37 | kth.chain_input_sequence(native) 38 | ); 39 | if (destroy) { 40 | destruct(native); 41 | } 42 | return obj; 43 | }; 44 | 45 | const fromData = (data) => { 46 | const native = kth.chain_input_factory_from_data(data); 47 | const valid = kth.chain_input_is_valid(native); 48 | if (!valid) { 49 | destruct(native); 50 | return new result.Result(undefined, false); 51 | } 52 | const obj = fromNative(native); 53 | destruct(native); 54 | return new result.Result(obj, true); 55 | }; 56 | 57 | const toData = (obj, wire) => { 58 | const native = obj.toNative(); 59 | const res = kth.chain_input_to_data(native, wire); 60 | destruct(native); 61 | return res; 62 | }; 63 | 64 | const memoizedToData = memoize(toData); 65 | 66 | const destruct = (native) => { 67 | kth.chain_input_destruct(native); 68 | }; 69 | 70 | exports.fromNative = fromNative; 71 | exports.fromData = fromData; 72 | exports.destruct = destruct; 73 | exports.Input = Input; 74 | -------------------------------------------------------------------------------- /test/chain/output.test.js: -------------------------------------------------------------------------------- 1 | const output = require('../../src/chain/output'); 2 | const enc = require('../../src/encoding'); 3 | const num = require('../../src/numerics'); 4 | const script = require('../../src/chain/script'); 5 | 6 | test('construct using fromData()', () => { 7 | // // Output end 8 | // "00f2052a01000000" // 8 Amount 9 | // "43" // 1 Script size 0x43 = 67 10 | // "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" 11 | // // Output end 12 | 13 | const scriptStr = 14 | '4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac'; 15 | 16 | const outputStr = 17 | '00f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac'; 18 | 19 | const outputBytes = enc.hexStrToBytes(outputStr); 20 | const result = output.fromData(outputBytes); 21 | expect(result.ok).toBe(true); 22 | const o = result.obj; 23 | 24 | expect(o.value).toBe(num.toSatoshis(50)); 25 | expect(enc.bytesToHexStr(o.script.rawData())).toBe(scriptStr); 26 | expect(enc.bytesToHexStr(o.rawData())).toBe(outputStr); 27 | }); 28 | 29 | test('construct using main constructor', () => { 30 | const scriptStr = 31 | '4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac'; 32 | const scriptBytes = enc.hexStrToBytes(scriptStr); 33 | const result = script.fromData(scriptBytes, false); 34 | expect(result.ok).toBe(true); 35 | const s = result.obj; 36 | 37 | const o = new output.Output(num.toSatoshis(50), s); 38 | expect(o.value).toBe(num.toSatoshis(50)); 39 | expect(enc.bytesToHexStr(o.script.rawData())).toBe(scriptStr); 40 | expect(enc.bytesToHexStr(o.rawData())).toBe( 41 | '00f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac' 42 | ); 43 | }); 44 | -------------------------------------------------------------------------------- /src/node.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const Promise = require('bluebird'); 7 | const chain = require('./chain/chain'); 8 | 9 | const async_node = { 10 | init_run_and_wait_for_signal: (...args) => { 11 | return new Promise((resolve) => { 12 | kth.node_init_run_and_wait_for_signal(...args, (err) => { 13 | resolve(err); 14 | }); 15 | }); 16 | } 17 | }; 18 | 19 | class Node { 20 | constructor(settings, stdoutEnabled) { 21 | this.native = kth.node_construct(settings, stdoutEnabled); 22 | this.chain_ = null; 23 | } 24 | 25 | get chain() { 26 | if ( ! this.native) return undefined; 27 | if ( ! this.chain_) { 28 | this.chain_ = new chain.Chain(kth.node_get_chain(this.native), this.native); 29 | } 30 | return this.chain_; 31 | } 32 | 33 | close() { 34 | kth.node_signal_stop(this.native); 35 | kth.node_destruct(this.native); 36 | this.native = null; 37 | } 38 | 39 | async launch(mods) { 40 | const res = await async_node.init_run_and_wait_for_signal(this.native, mods); 41 | return res; 42 | } 43 | 44 | get capi_version() { 45 | return kth.node_capi_version(); 46 | } 47 | 48 | get cppapi_version() { 49 | return kth.node_cppapi_version(); 50 | } 51 | 52 | // get js_native_version() { 53 | // return kth.node_js_native_version(); //TODO: implement on native side 54 | // } 55 | 56 | get version() { 57 | return process.env.npm_package_version; 58 | } 59 | 60 | get microarchitecture() { 61 | return kth.node_microarchitecture(); 62 | } 63 | 64 | get march_names() { 65 | return kth.node_march_names(); 66 | } 67 | 68 | get currency_symbol() { 69 | return kth.node_currency_symbol(); 70 | } 71 | 72 | get currency() { 73 | return kth.node_currency(); 74 | } 75 | 76 | // get db_type() { 77 | // return kth.node_db_type(); 78 | // } 79 | } 80 | 81 | exports.Node = Node; 82 | -------------------------------------------------------------------------------- /examples/subscribe.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | /* eslint-disable */ 6 | 7 | // const kth = require("@knuth/bch") 8 | const kth = require('../src/kth'); 9 | 10 | let running_ = false; 11 | 12 | async function main() { 13 | process.on('SIGINT', shutdown); 14 | const config = kth.settings.getDefault(kth.network.chipnet); 15 | const node = new kth.node.Node(config, false); 16 | await node.launch(kth.startModules.all); 17 | console.log("Knuth node has been launched."); 18 | running_ = true; 19 | 20 | node.chain.subscribeBlockchain((e, height, incomingBlocks, outgoingBlocks) => { 21 | if (e !== kth.errors.success) { 22 | console.log(`Error: ${e}`); 23 | return false; 24 | } 25 | 26 | if ( ! running_) { 27 | return false; 28 | } 29 | 30 | 31 | if (incomingBlocks.length > 0) { 32 | console.log("new tip height: ", height + incomingBlocks.length); 33 | } 34 | 35 | if (outgoingBlocks && outgoingBlocks.length > 0) { 36 | console.log("outgoingBlocks: ", outgoingBlocks); 37 | } 38 | 39 | return true; 40 | }); 41 | 42 | node.chain.subscribeTransaction((e, tx) => { 43 | if (e !== kth.errors.success) { 44 | console.log(`Error: ${e}`); 45 | return false; 46 | } 47 | 48 | if ( ! running_) { 49 | return false; 50 | } 51 | 52 | 53 | if (tx !== null) { 54 | console.log("Received Transaction: ", tx); 55 | } 56 | 57 | return true; 58 | }); 59 | 60 | 61 | while (running_) { 62 | await sleep(1000); 63 | } 64 | 65 | console.log("Shutting down ..."); 66 | 67 | node.close(); 68 | console.log("Good bye!"); 69 | } 70 | 71 | function shutdown() { 72 | console.log('Graceful shutdown ...'); 73 | running_ = false; 74 | } 75 | 76 | function sleep(ms) { 77 | return new Promise((r) => setTimeout(r, ms)); 78 | } 79 | 80 | (async () => { 81 | try { 82 | await main(); 83 | } catch (e) { 84 | console.log(e); 85 | } 86 | })(); 87 | -------------------------------------------------------------------------------- /test/encoding.test.js: -------------------------------------------------------------------------------- 1 | const enc = require('../src/encoding'); 2 | 3 | test('fromData() and toData()', () => { 4 | const str1 = 5 | '000000206f02957eb726a4a50fc471cb15e25099f6af5a976044a5fae905580800000000f1bb8753254766f2ebea2657aa991782fdd2c99a43db0230b51058421373ba9b93a7445fa3c16e1c59c3b224'; 6 | const bytes1 = enc.hexStrToBytes(str1); 7 | const str2 = enc.bytesToHexStr(bytes1); 8 | 9 | expect(str2).toEqual(str1); 10 | expect(str2).toBe(str1); 11 | }); 12 | 13 | test('reverseStr()', () => { 14 | const str1 = 15 | '000000206f02957eb726a4a50fc471cb15e25099f6af5a976044a5fae905580800000000f1bb8753254766f2ebea2657aa991782fdd2c99a43db0230b51058421373ba9b93a7445fa3c16e1c59c3b224'; 16 | const reversed = enc.reverseStr(str1); 17 | const str2 = enc.reverseStr(reversed); 18 | 19 | expect(str1).toEqual(str2); 20 | }); 21 | 22 | test('Hash encoding', () => { 23 | const genesisStr = '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'; 24 | const genesisBytes = enc.Hash.strToBytes(genesisStr); 25 | expect(genesisBytes).toEqual( 26 | new Uint8Array([ 27 | 111, 28 | 226, 29 | 140, 30 | 10, 31 | 182, 32 | 241, 33 | 179, 34 | 114, 35 | 193, 36 | 166, 37 | 162, 38 | 70, 39 | 174, 40 | 99, 41 | 247, 42 | 79, 43 | 147, 44 | 30, 45 | 131, 46 | 101, 47 | 225, 48 | 90, 49 | 8, 50 | 156, 51 | 104, 52 | 214, 53 | 25, 54 | 0, 55 | 0, 56 | 0, 57 | 0, 58 | 0 59 | ]) 60 | ); 61 | const clone = enc.Hash.bytesToStr(genesisBytes); 62 | expect(genesisStr).toEqual(clone); 63 | }); 64 | 65 | test('nullHash encoding', () => { 66 | expect(enc.Hash.nullHash()).toEqual( 67 | new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 68 | ); 69 | expect(enc.Hash.bytesToStr(enc.Hash.nullHash())).toEqual( 70 | '0000000000000000000000000000000000000000000000000000000000000000' 71 | ); 72 | }); 73 | -------------------------------------------------------------------------------- /test/config/networkSettings.test.js: -------------------------------------------------------------------------------- 1 | const networkSettings = require('../../src/config/networkSettings'); 2 | const network = require('../../src/config/network'); 3 | 4 | test('read default settings', () => { 5 | const settings = networkSettings.getDefault(network.Network.mainnet); 6 | expect(settings.threads).toBe(0); 7 | expect(settings.protocolMaximum).toBe(70015); 8 | expect(settings.protocolMinimum).toBe(31402); 9 | expect(settings.services).toBe(1); 10 | expect(settings.invalidServices).toBe(0); 11 | expect(settings.relayTransactions).toBe(true); 12 | expect(settings.validateChecksum).toBe(false); 13 | expect(settings.identifier).toBe(3908297187); 14 | expect(settings.inboundPort).toBe(8333); 15 | expect(settings.inboundConnections).toBe(0); 16 | expect(settings.outboundConnections).toBe(8); 17 | expect(settings.manualAttemptLimit).toBe(0); 18 | expect(settings.connectBatchSize).toBe(5); 19 | expect(settings.connectTimeoutSeconds).toBe(5); 20 | expect(settings.channelHandshakeSeconds).toBe(6000); 21 | expect(settings.channelHeartbeatMinutes).toBe(5); 22 | expect(settings.channelInactivityMinutes).toBe(10); 23 | expect(settings.channelExpirationMinutes).toBe(60); 24 | expect(settings.channelGerminationSeconds).toBe(30); 25 | expect(settings.hostPoolCapacity).toBe(1000); 26 | expect(settings.hostsFile).toBe('hosts.cache'); 27 | // expect(settings.self.ip).toBe('0.0.0.0'); 28 | expect(settings.self.port).toBe(0); 29 | expect(settings.blacklist.length).toBe(0); 30 | expect(settings.peers.length).toBe(0); 31 | expect(settings.seeds.length).toBe(6); 32 | expect(settings.seeds[0].scheme).toBe(''); 33 | expect(settings.seeds[0].host).toBe('seed.flowee.cash'); 34 | expect(settings.seeds[0].port).toBe(8333); 35 | expect(settings.debugFile).toBe('debug.log'); 36 | expect(settings.errorFile).toBe('error.log'); 37 | expect(settings.archiveDirectory).toBe('archive'); 38 | expect(settings.rotationSize).toBe(0); 39 | expect(settings.minimumFreeSpace).toBe(0); 40 | expect(settings.maximumArchiveSize).toBe(0); 41 | expect(settings.maximumArchiveFiles).toBe(0); 42 | // expect(settings.statisticsServer.ip).toBe('0.0.0.0'); 43 | expect(settings.statisticsServer.port).toBe(0); 44 | expect(settings.verbose).toBe(false); 45 | expect(settings.useIpv6).toBe(true); 46 | expect(settings.userAgentBlacklist.length).toBe(1); 47 | expect(settings.userAgentBlacklist[0]).toBe('/Bitcoin SV:'); 48 | }); 49 | -------------------------------------------------------------------------------- /test/chain/header.test.js: -------------------------------------------------------------------------------- 1 | const header = require('../../src/chain/header'); 2 | const enc = require('../../src/encoding'); 3 | 4 | test('construct using fromData()', () => { 5 | const genesisStr = 6 | '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c00'; 7 | const genesisBytes = enc.hexStrToBytes(genesisStr); 8 | const result = header.fromData(1, genesisBytes); 9 | expect(result.ok).toBe(true); 10 | const h = result.obj; 11 | const hashStr = enc.Hash.bytesToStr(h.hash); 12 | expect(hashStr).toBe('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'); 13 | expect(enc.fix(h.hash)).toEqual( 14 | enc.Hash.strToBytes('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f') 15 | ); 16 | expect(h.version).toBe(1); 17 | expect(enc.fix(h.previousBlockHash)).toEqual(enc.Hash.nullHash()); 18 | expect(enc.fix(h.merkle)).toEqual( 19 | enc.Hash.strToBytes('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b') 20 | ); 21 | expect(h.timestamp).toBe(1231006505); 22 | expect(h.bits).toBe(0x1d00ffff); 23 | expect(h.nonce).toBe(2083236893); 24 | expect(enc.bytesToHexStr(h.rawData(1))).toBe(genesisStr); 25 | }); 26 | 27 | test('construct using main constructor', () => { 28 | const previousBlockHash = enc.Hash.nullHash(); 29 | const merkle = enc.Hash.strToBytes('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'); 30 | const h = new header.Header(1, previousBlockHash, merkle, 1231006505, 0x1d00ffff, 2083236893); 31 | 32 | expect(enc.Hash.bytesToStr(h.hash)).toBe('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'); 33 | expect(enc.Hash.bytesToStr(h.hash)).toEqual('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'); 34 | expect(h.version).toBe(1); 35 | expect(enc.Hash.bytesToStr(h.previousBlockHash)).toEqual( 36 | '0000000000000000000000000000000000000000000000000000000000000000' 37 | ); 38 | expect(enc.Hash.bytesToStr(h.merkle)).toEqual('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'); 39 | expect(h.timestamp).toBe(1231006505); 40 | expect(h.bits).toBe(0x1d00ffff); 41 | expect(h.nonce).toBe(2083236893); 42 | expect(enc.bytesToHexStr(h.rawData(1))).toBe( 43 | '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c00' 44 | ); 45 | }); 46 | -------------------------------------------------------------------------------- /src/chain/header.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const memoize = require('memoizee'); 7 | const result = require('../result'); 8 | 9 | class Header { 10 | constructor(version, previousBlockHash, merkle, timestamp, bits, nonce) { 11 | this.version = version; 12 | this.previousBlockHash = previousBlockHash; 13 | this.merkle = merkle; 14 | this.timestamp = timestamp; 15 | this.bits = bits; 16 | this.nonce = nonce; 17 | } 18 | 19 | toNative() { 20 | const native = kth.chain_header_construct( 21 | this.version, 22 | this.previousBlockHash, 23 | this.merkle, 24 | this.timestamp, 25 | this.bits, 26 | this.nonce 27 | ); 28 | return native; 29 | } 30 | 31 | get hash() { 32 | const res = memoizedHash(this); 33 | return res; 34 | } 35 | 36 | rawData(version) { 37 | const res = memoizedToData(this, version); 38 | return res; 39 | } 40 | } 41 | 42 | const fromNative = (native, destroy = false) => { 43 | const obj = new Header( 44 | kth.chain_header_version(native), 45 | kth.chain_header_previous_block_hash(native), 46 | kth.chain_header_merkle(native), 47 | kth.chain_header_timestamp(native), 48 | kth.chain_header_bits(native), 49 | kth.chain_header_nonce(native) 50 | ); 51 | if (destroy) { 52 | destruct(native); 53 | } 54 | return obj; 55 | }; 56 | 57 | const fromData = (version, data) => { 58 | const native = kth.chain_header_factory_from_data(version, data); 59 | const valid = kth.chain_header_is_valid(native); 60 | if (!valid) { 61 | destruct(native); 62 | return new result.Result(undefined, false); 63 | } 64 | const obj = fromNative(native); 65 | destruct(native); 66 | return new result.Result(obj, true); 67 | }; 68 | 69 | const toData = (obj, version) => { 70 | const native = obj.toNative(); 71 | const res = kth.chain_header_to_data(native, version); 72 | destruct(native); 73 | return res; 74 | }; 75 | 76 | const hash = (obj) => { 77 | const native = obj.toNative(); 78 | const res = kth.chain_header_hash(native); 79 | destruct(native); 80 | return res; 81 | }; 82 | 83 | const memoizedToData = memoize(toData); 84 | const memoizedHash = memoize(hash); 85 | 86 | const destruct = (native) => { 87 | kth.chain_header_destruct(native); 88 | }; 89 | 90 | exports.fromNative = fromNative; 91 | exports.fromData = fromData; 92 | exports.destruct = destruct; 93 | exports.hash = hash; 94 | exports.Header = Header; 95 | -------------------------------------------------------------------------------- /src/chain/transaction.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const memoize = require('memoizee'); 7 | const result = require('../result'); 8 | const outputList = require('./outputList'); 9 | const inputList = require('./inputList'); 10 | 11 | // kth_transaction_t kth_chain_transaction_construct(uint32_t version, uint32_t locktime, kth_input_list_t inputs, kth_output_list_t outputs); 12 | 13 | class Transaction { 14 | constructor(version, locktime, inputs, outputs) { 15 | this.version = version; 16 | this.locktime = locktime; 17 | this.inputs = inputs; 18 | this.outputs = outputs; 19 | } 20 | 21 | toNative() { 22 | const native = kth.chain_transaction_construct( 23 | this.version, 24 | this.locktime, 25 | inputList.toNative(this.inputs), 26 | outputList.toNative(this.outputs) 27 | ); 28 | return native; 29 | } 30 | 31 | get hash() { 32 | const res = memoizedHash(this); 33 | return res; 34 | } 35 | 36 | rawData(wire = true) { 37 | const res = memoizedToData(this, wire); 38 | return res; 39 | } 40 | } 41 | 42 | const fromNative = (native, destroy = false) => { 43 | const obj = new Transaction( 44 | kth.chain_transaction_version(native), 45 | kth.chain_transaction_locktime(native), 46 | inputList.fromNative(kth.chain_transaction_inputs(native)), 47 | outputList.fromNative(kth.chain_transaction_outputs(native)) 48 | ); 49 | if (destroy) { 50 | destruct(native); 51 | } 52 | return obj; 53 | }; 54 | 55 | const fromData = (version, data) => { 56 | const native = kth.chain_transaction_factory_from_data(version, data); 57 | const valid = kth.chain_transaction_is_valid(native); 58 | if (!valid) { 59 | destruct(native); 60 | return new result.Result(undefined, false); 61 | } 62 | const obj = fromNative(native); 63 | destruct(native); 64 | return new result.Result(obj, true); 65 | }; 66 | 67 | const toData = (obj, wire = true) => { 68 | const native = obj.toNative(); 69 | const res = kth.chain_transaction_to_data(native, wire); 70 | destruct(native); 71 | return res; 72 | }; 73 | 74 | const hash = (obj) => { 75 | const native = obj.toNative(); 76 | const res = kth.chain_transaction_hash(native); 77 | destruct(native); 78 | return res; 79 | }; 80 | 81 | const memoizedToData = memoize(toData); 82 | const memoizedHash = memoize(hash); 83 | 84 | const destruct = (native) => { 85 | kth.chain_transaction_destruct(native); 86 | }; 87 | 88 | exports.fromNative = fromNative; 89 | exports.fromData = fromData; 90 | exports.destruct = destruct; 91 | exports.hash = hash; 92 | exports.Transaction = Transaction; 93 | -------------------------------------------------------------------------------- /test/chain/input.test.js: -------------------------------------------------------------------------------- 1 | const input = require('../../src/chain/input'); 2 | const enc = require('../../src/encoding'); 3 | const outputPoint = require('../../src/chain/outputPoint'); 4 | const script = require('../../src/chain/script'); 5 | 6 | test('construct using fromData()', () => { 7 | // // Input start 8 | // "0000000000000000000000000000000000000000000000000000000000000000ffffffff" // 36 (32+4) Previous Outpoint 9 | // "4d" // 1 Script size 0x4d = 77 10 | // "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73" 11 | // "ffffffff" // 4 sequence 12 | // // Input end 13 | 14 | const scriptStr = 15 | '04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73'; 16 | 17 | const inputStr = 18 | '0000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff'; 19 | 20 | const inputBytes = enc.hexStrToBytes(inputStr); 21 | const result = input.fromData(inputBytes); 22 | expect(result.ok).toBe(true); 23 | const i = result.obj; 24 | 25 | expect(i.previousOutpoint.index).toBe(0xffffffff); 26 | expect(enc.Hash.bytesToStr(i.previousOutpoint.hash)).toBe( 27 | '0000000000000000000000000000000000000000000000000000000000000000' 28 | ); 29 | expect(enc.bytesToHexStr(i.script.rawData())).toBe(scriptStr); 30 | expect(i.sequence).toBe(0xffffffff); 31 | expect(enc.bytesToHexStr(i.rawData())).toBe(inputStr); 32 | }); 33 | 34 | test('construct using main constructor', () => { 35 | const scriptStr = 36 | '04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73'; 37 | const scriptBytes = enc.hexStrToBytes(scriptStr); 38 | const result = script.fromData(scriptBytes, false); 39 | expect(result.ok).toBe(true); 40 | const s = result.obj; 41 | 42 | const previousOutpoint = new outputPoint.OutputPoint(enc.Hash.nullHash(), 0xffffffff); 43 | 44 | const i = new input.Input(previousOutpoint, s, 0xffffffff); 45 | expect(i.previousOutpoint.index).toBe(0xffffffff); 46 | expect(enc.Hash.bytesToStr(i.previousOutpoint.hash)).toBe( 47 | '0000000000000000000000000000000000000000000000000000000000000000' 48 | ); 49 | expect(enc.bytesToHexStr(i.script.rawData())).toBe(scriptStr); 50 | expect(i.sequence).toBe(0xffffffff); 51 | expect(enc.bytesToHexStr(i.rawData())).toBe( 52 | '0000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff' 53 | ); 54 | }); 55 | -------------------------------------------------------------------------------- /examples/subscription/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const express = require('express'); 6 | const path = require('path'); 7 | const app = express(); 8 | // const kth = require("@knuth/bch"); 9 | const kth = require('../../src/kth'); 10 | 11 | app.use(express.static(path.join(__dirname, '.'))); 12 | 13 | let running_ = false; 14 | let lastBlockHeight = 0; // to store last block height 15 | 16 | const config = kth.settings.getDefault(kth.network.chipnet); 17 | const node = new kth.node.Node(config, true); 18 | 19 | 20 | function sleep(ms) { 21 | return new Promise((r) => setTimeout(r, ms)); 22 | } 23 | 24 | app.get('/sse-endpoint', (req, res) => { 25 | res.setHeader('Content-Type', 'text/event-stream'); 26 | res.setHeader('Cache-Control', 'no-cache'); 27 | res.setHeader('Connection', 'keep-alive'); 28 | res.flushHeaders(); 29 | 30 | res.write(`event: blockheight\ndata: ${lastBlockHeight}\n\n`); 31 | 32 | let connected = true; 33 | 34 | node.chain.subscribeBlockchain((e, height, incomingBlocks, outgoingBlocks) => { 35 | // console.log("subscribeBlockchain: ", e, height); 36 | if (e !== kth.errors.success) { 37 | console.log(`Error: ${e}`); 38 | return false; 39 | } 40 | 41 | if ( ! running_) { 42 | console.log("Not running, returning false"); 43 | return false; 44 | } 45 | 46 | if (incomingBlocks.length > 0) { 47 | lastBlockHeight = height + incomingBlocks.length; 48 | console.log(`${new Date().toISOString()} - Received new block. Height: ${lastBlockHeight}`); 49 | res.write(`event: blockheight\ndata: ${lastBlockHeight}\n\n`); 50 | } 51 | 52 | return connected; 53 | }); 54 | 55 | req.on('close', () => { 56 | connected = false; 57 | res.end(); 58 | }); 59 | }); 60 | 61 | const server = app.listen(3000, () => { 62 | console.log('Server is running on http://localhost:3000'); 63 | }); 64 | 65 | async function main() { 66 | process.on('SIGINT', shutdown); 67 | await node.launch(kth.startModules.all); 68 | console.log("Knuth node has been launched."); 69 | running_ = true; 70 | 71 | const [_, height] = await node.chain.getLastHeight(); 72 | lastBlockHeight = height; 73 | 74 | while (running_) { 75 | // console.log("sleeping...") 76 | await sleep(1000); 77 | } 78 | 79 | console.log("Shutting down Knuth node..."); 80 | node.close(); 81 | console.log("Shutting down Web server..."); 82 | 83 | server.close(() => { 84 | console.log("Good bye!"); 85 | process.exit(); 86 | }); 87 | } 88 | 89 | function shutdown() { 90 | console.log(''); 91 | console.log('Ctrl+C detected.'); 92 | running_ = false; 93 | } 94 | 95 | (async () => { 96 | try { 97 | await main(); 98 | } catch (e) { 99 | console.log(e); 100 | } 101 | })(); 102 | -------------------------------------------------------------------------------- /examples/subscription/index_just_one_sub.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const express = require('express'); 6 | const path = require('path'); 7 | const app = express(); 8 | // const kth = require("@knuth/bch"); 9 | const kth = require('../../src/kth'); 10 | 11 | app.use(express.static(path.join(__dirname, '.'))); 12 | 13 | let running_ = false; 14 | let lastBlockHeight = 0; // to store last block height 15 | 16 | function sleep(ms) { 17 | return new Promise((r) => setTimeout(r, ms)); 18 | } 19 | 20 | app.get('/sse-endpoint', (req, res) => { 21 | res.setHeader('Content-Type', 'text/event-stream'); 22 | res.setHeader('Cache-Control', 'no-cache'); 23 | res.setHeader('Connection', 'keep-alive'); 24 | res.flushHeaders(); 25 | 26 | res.write(`event: blockheight\ndata: ${lastBlockHeight}\n\n`); 27 | let lastSentHeight = lastBlockHeight; 28 | 29 | const intervalId = setInterval(() => { 30 | if (lastSentHeight !== lastBlockHeight) { 31 | res.write(`event: blockheight\ndata: ${lastBlockHeight}\n\n`); 32 | lastSentHeight = lastBlockHeight; 33 | } 34 | }, 500); 35 | 36 | req.on('close', () => { 37 | clearInterval(intervalId); 38 | res.end(); 39 | }); 40 | }); 41 | 42 | const server = app.listen(3000, () => { 43 | console.log('Server is running on http://localhost:3000'); 44 | }); 45 | 46 | async function main() { 47 | process.on('SIGINT', shutdown); 48 | const config = kth.settings.getDefault(kth.network.chipnet); 49 | const node = new kth.node.Node(config, true); 50 | await node.launch(kth.startModules.all); 51 | console.log("Knuth node has been launched."); 52 | running_ = true; 53 | 54 | const [_, height] = await node.chain.getLastHeight(); 55 | lastBlockHeight = height; 56 | 57 | node.chain.subscribeBlockchain((e, height, incomingBlocks, outgoingBlocks) => { 58 | // console.log("subscribeBlockchain: ", e, height, incomingBlocks, outgoingBlocks); 59 | if (e !== kth.errors.success) { 60 | console.log(`Error: ${e}`); 61 | return false; 62 | } 63 | 64 | if ( ! running_) { 65 | console.log("Not running, returning false"); 66 | return false; 67 | } 68 | 69 | if (incomingBlocks && incomingBlocks.length > 0) { 70 | lastBlockHeight = height + incomingBlocks.length; 71 | console.log(`${new Date().toISOString()} - Received new block. Height: ${lastBlockHeight}`); 72 | } 73 | 74 | // console.log("returning true"); 75 | return true; 76 | }); 77 | 78 | while (running_) { 79 | // console.log("sleeping...") 80 | await sleep(1000); 81 | } 82 | 83 | console.log("Shutting down Knuth node..."); 84 | node.close(); 85 | console.log("Shutting down Web server..."); 86 | 87 | server.close(() => { 88 | console.log("Good bye!"); 89 | process.exit(); 90 | }); 91 | } 92 | 93 | function shutdown() { 94 | console.log(''); 95 | console.log('Ctrl+C detected.'); 96 | running_ = false; 97 | } 98 | 99 | (async () => { 100 | try { 101 | await main(); 102 | } catch (e) { 103 | console.log(e); 104 | } 105 | })(); 106 | -------------------------------------------------------------------------------- /test/wallet/paymentAddress.test.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const paymentAddress = require('../../src/wallet/paymentAddress'); 6 | 7 | it('should fail when address is empty', () => { 8 | const result = paymentAddress.fromString(''); 9 | expect(result.ok).toBe(false); 10 | }); 11 | 12 | it('should fail when address is whitespace', () => { 13 | const result = paymentAddress.fromString(' '); 14 | expect(result.ok).toBe(false); 15 | }); 16 | 17 | it('should fail when address is invalid', () => { 18 | const result = paymentAddress.fromString('abcd'); 19 | expect(result.ok).toBe(false); 20 | }); 21 | 22 | it('should handle mainnet cashaddr address correctly', () => { 23 | const isVal = paymentAddress.isValid('bitcoincash:qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 24 | expect(isVal).toBe(true); 25 | 26 | const result = paymentAddress.fromString('bitcoincash:qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 27 | expect(result.ok).toBe(true); 28 | const addr = result.obj; 29 | expect(addr.encoded()).toBe('bitcoincash:qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 30 | expect(addr.encodedCashAddr()).toBe('bitcoincash:qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 31 | expect(addr.encodedCashTokens()).toBe('bitcoincash:zrcuqadqrzp2uztjl9wn5sthepkg22majypyxk429j'); 32 | expect(addr.encodedLegacy()).toBe('1P3GQYtcWgZHrrJhUa4ctoQ3QoCU2F65nz'); 33 | }); 34 | 35 | it('should handle mainnet cashaddr address without prefix correctly', () => { 36 | const isVal = paymentAddress.isValid('qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 37 | expect(isVal).toBe(true); 38 | 39 | const result = paymentAddress.fromString('qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 40 | expect(result.ok).toBe(true); 41 | const addr = result.obj; 42 | expect(addr.encoded()).toBe('bitcoincash:qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 43 | expect(addr.encodedCashAddr()).toBe('bitcoincash:qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 44 | expect(addr.encodedCashTokens()).toBe('bitcoincash:zrcuqadqrzp2uztjl9wn5sthepkg22majypyxk429j'); 45 | expect(addr.encodedLegacy()).toBe('1P3GQYtcWgZHrrJhUa4ctoQ3QoCU2F65nz'); 46 | }); 47 | 48 | it('should handle mainnet legacy address correctly', () => { 49 | const isVal = paymentAddress.isValid('1P3GQYtcWgZHrrJhUa4ctoQ3QoCU2F65nz'); 50 | expect(isVal).toBe(true); 51 | 52 | const result = paymentAddress.fromString('1P3GQYtcWgZHrrJhUa4ctoQ3QoCU2F65nz'); 53 | expect(result.ok).toBe(true); 54 | const addr = result.obj; 55 | expect(addr.encoded()).toBe('bitcoincash:qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 56 | expect(addr.encodedCashAddr()).toBe('bitcoincash:qrcuqadqrzp2uztjl9wn5sthepkg22majyxw4gmv6p'); 57 | expect(addr.encodedCashTokens()).toBe('bitcoincash:zrcuqadqrzp2uztjl9wn5sthepkg22majypyxk429j'); 58 | expect(addr.encodedLegacy()).toBe('1P3GQYtcWgZHrrJhUa4ctoQ3QoCU2F65nz'); 59 | }); 60 | 61 | it('should handle 32-byte CashAddr correctly for mainnet', () => { 62 | const isVal = paymentAddress.isValid('bitcoincash:pvstqkm54dtvnpyqxt5m5n7sjsn4enrlxc526xyxlnjkaycdzfeu69reyzmqx'); 63 | expect(isVal).toBe(true); 64 | 65 | const result = paymentAddress.fromString('bitcoincash:pvstqkm54dtvnpyqxt5m5n7sjsn4enrlxc526xyxlnjkaycdzfeu69reyzmqx'); 66 | expect(result.ok).toBe(true); 67 | const addr = result.obj; 68 | expect(addr.encodedCashAddr()).toBe('bitcoincash:pvstqkm54dtvnpyqxt5m5n7sjsn4enrlxc526xyxlnjkaycdzfeu69reyzmqx'); 69 | expect(addr.encodedCashTokens()).toBe('bitcoincash:rvstqkm54dtvnpyqxt5m5n7sjsn4enrlxc526xyxlnjkaycdzfeu6hs99m6ed'); 70 | expect(addr.encodedLegacy()).toBe('34frpCV2v6wtzig9xx4Z9XJ6s4jU3zqwR7');// In fact a 32-byte address is not representable in legacy encoding. 71 | }); 72 | -------------------------------------------------------------------------------- /src/chain/block.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const memoize = require('memoizee'); 7 | const header = require('./header'); 8 | const result = require('../result'); 9 | const transactionList = require('./transactionList'); 10 | 11 | class Block { 12 | constructor(header, transactions) { 13 | this.header = header; 14 | this.transactions = transactions; 15 | } 16 | 17 | toNative() { 18 | const native = kth.chain_block_construct(this.header.toNative(), transactionList.toNative(this.transactions)); 19 | return native; 20 | } 21 | 22 | get hash() { 23 | const res = memoizedHash(this); 24 | return res; 25 | } 26 | 27 | rawData(wire = true) { 28 | const res = memoizedToData(this, wire); 29 | return res; 30 | } 31 | } 32 | 33 | const fromNative = (native, destroy = false) => { 34 | const obj = new Block( 35 | header.fromNative(kth.chain_block_header(native)), 36 | transactionList.fromNative(kth.chain_block_transactions(native)) 37 | ); 38 | if (destroy) { 39 | destruct(native); 40 | } 41 | return obj; 42 | 43 | // console.log(native); 44 | 45 | // const headerNative = kth.chain_block_header(native); 46 | // console.log(headerNative); 47 | // const version = kth.chain_header_version(headerNative); 48 | // console.log(version); 49 | // // const prevHash = kth.chain_header_previous_block_hash(headerNative); 50 | // // console.log(prevHash); 51 | // // const merkle = kth.chain_header_merkle(headerNative); 52 | // // console.log(merkle); 53 | // // const timestamp = kth.chain_header_timestamp(headerNative); 54 | // // console.log(timestamp); 55 | // // const bits = kth.chain_header_bits(headerNative); 56 | // // console.log(bits); 57 | // // const nonce = kth.chain_header_nonce(headerNative); 58 | // // console.log(nonce); 59 | 60 | 61 | // // const h = header.fromNative(kth.chain_block_header(native)); 62 | // // console.log(h); 63 | // // const txs = transactionList.fromNative(kth.chain_block_transactions(native)); 64 | // // console.log(txs); 65 | // // const obj = new Block( 66 | // // header.fromNative(kth.chain_block_header(native)), 67 | // // transactionList.fromNative(kth.chain_block_transactions(native)) 68 | // // ); 69 | // if (destroy) { 70 | // destruct(native); 71 | // } 72 | // // return obj; 73 | // return undefined; 74 | }; 75 | 76 | const fromData = (version, data) => { 77 | const native = kth.chain_block_factory_from_data(version, data); 78 | const valid = kth.chain_block_is_valid(native); 79 | if (!valid) { 80 | destruct(native); 81 | return new result.Result(undefined, false); 82 | } 83 | const obj = fromNative(native); 84 | destruct(native); 85 | return new result.Result(obj, true); 86 | }; 87 | 88 | const toData = (obj, wire = true) => { 89 | const native = obj.toNative(); 90 | const res = kth.chain_block_to_data(native, wire); 91 | destruct(native); 92 | return res; 93 | }; 94 | 95 | const hash = (obj) => { 96 | const native = obj.toNative(); 97 | const res = kth.chain_block_hash(native); 98 | destruct(native); 99 | return res; 100 | }; 101 | 102 | const memoizedToData = memoize(toData); 103 | const memoizedHash = memoize(hash); 104 | 105 | const destruct = (native) => { 106 | kth.chain_block_destruct(native); 107 | }; 108 | 109 | exports.fromNative = fromNative; 110 | exports.fromData = fromData; 111 | exports.destruct = destruct; 112 | exports.hash = hash; 113 | exports.Block = Block; 114 | -------------------------------------------------------------------------------- /src/config/settings.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | import { Network } from './network'; 6 | 7 | export interface Checkpoint { 8 | hash: Uint8Array; 9 | height: number; 10 | } 11 | 12 | export interface Authority { 13 | ip: string; 14 | port: number; 15 | } 16 | 17 | export interface Endpoint { 18 | scheme: string; 19 | host: string; 20 | port: number; 21 | } 22 | 23 | export interface NodeSettings { 24 | syncPeers: number; 25 | syncTimeoutSeconds: number; 26 | blockLatencySeconds: number; 27 | refreshTransactions: boolean; 28 | compactBlocksHighBandwidth: boolean; 29 | } 30 | 31 | export interface BlockchainSettings { 32 | cores: number; 33 | priority: boolean; 34 | byteFeeSatoshis: number; 35 | sigopFeeSatoshis: number; 36 | minimumOutputSatoshis: number; 37 | 38 | notifyLimitHours: number; 39 | reorganizationLimit: number; 40 | 41 | checkpoints: Array; 42 | 43 | fixCheckpoints: boolean; 44 | allowCollisions: boolean; 45 | easyBlocks: boolean; 46 | retarget: boolean; 47 | bip16: boolean; 48 | bip30: boolean; 49 | bip34: boolean; 50 | bip66: boolean; 51 | bip65: boolean; 52 | bip90: boolean; 53 | bip68: boolean; 54 | bip112: boolean; 55 | bip113: boolean; 56 | bchUahf: boolean; 57 | bchDaaCw144: boolean; 58 | bchPythagoras: boolean; 59 | bchEuclid: boolean; 60 | bchPisano: boolean; 61 | bchMersenne: boolean; 62 | bchFermat: boolean; 63 | bchEuler: boolean; 64 | bchGauss: boolean; 65 | bchDescartes: boolean; 66 | bchLobachevski: boolean; 67 | 68 | galoisActivationTime: number; 69 | leibnizActivationTime: number; 70 | 71 | asertHalfLife: number; 72 | } 73 | 74 | export interface DatabaseSettings { 75 | directory: string; 76 | dbMode: DbMode; 77 | reorgPoolLimit: number; 78 | dbMaxSize: number; 79 | safeMode: boolean; 80 | cacheCapacity: number; 81 | } 82 | 83 | export interface NetworkSettings { 84 | threads: number; 85 | 86 | protocolMaximum: number; 87 | protocolMinimum: number; 88 | services: number; 89 | invalidServices: number; 90 | 91 | relayTransactions: boolean; 92 | validateChecksum: boolean; 93 | 94 | identifier: number; 95 | inboundPort: number; 96 | inboundConnections: number; 97 | outboundConnections: number; 98 | manualAttemptLimit: number; 99 | connectBatchSize: number; 100 | connectTimeoutSeconds: number; 101 | channelHandshakeSeconds: number; 102 | channelHeartbeatMinutes: number; 103 | channelInactivityMinutes: number; 104 | channelExpirationMinutes: number; 105 | channelGerminationSeconds: number; 106 | hostPoolCapacity: number; 107 | 108 | hostsFile: string; 109 | 110 | self: Authority; 111 | blacklist: Array; 112 | 113 | peers: Array; 114 | seeds: Array; 115 | 116 | debugFile: string; 117 | errorFile: string; 118 | archiveDirectory: string; 119 | 120 | rotationSize: number; 121 | minimumFreeSpace: number; 122 | maximumArchiveSize: number; 123 | maximumArchiveFiles: number; 124 | 125 | statisticsServer: Authority; 126 | 127 | verbose: boolean; 128 | useIpv6: boolean; 129 | 130 | userAgentBlacklist: Array; 131 | } 132 | 133 | export interface Settings { 134 | node: NodeSettings; 135 | chain: BlockchainSettings; 136 | database: DatabaseSettings; 137 | network: NetworkSettings; 138 | } 139 | 140 | export interface SettingsResult { 141 | ok: boolean; 142 | message?: string; 143 | settings?: Settings; 144 | } 145 | 146 | export declare function getDefault(network : Network): Settings; 147 | 148 | export declare function getFromFile(file : string): SettingsResult; 149 | -------------------------------------------------------------------------------- /test/wallet/wallet.test.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const { Wallet } = require('../../src/wallet/wallet'); 6 | const { PaymentAddress } = require('../../src/wallet/paymentAddress'); 7 | 8 | describe('Wallet', () => { 9 | const TEST_MNEMONIC = [ 10 | 'car', 'slab', 'tail', 'dirt', 'wife', 'custom', 'front', 11 | 'shield', 'diet', 'pear', 'skull', 'vapor', 'gorilla', 'token', 'yard' 12 | ]; 13 | 14 | const TEST_DERIVATION_PATH = "m/44'/145'/0'/0"; 15 | const TEST_NETWORK = 'MAINNET'; //'TESTNET'; 16 | 17 | let wallet; 18 | 19 | beforeEach(() => { 20 | wallet = new Wallet(TEST_MNEMONIC, TEST_DERIVATION_PATH, TEST_NETWORK); 21 | }); 22 | 23 | test('should correctly instantiate with given mnemonic, derivation path, and network', () => { 24 | expect(wallet).toBeInstanceOf(Wallet); 25 | }); 26 | 27 | test('rootKey should return expected BIP32 root key', () => { 28 | const rootKey = wallet.rootKey; 29 | expect(typeof rootKey).toBe('string'); 30 | expect(rootKey).toBe('xprv9s21ZrQH143K2DQjFCenT6uLwd7dNoMKXEsiQ2v5EkNFGd54wN9td5GnDKLR1amKpXFPwHBHdUNL3uowUZd4jZtFEbSG73wEyPrYn9sfbNN'); 31 | }); 32 | 33 | test('extendedPrivateKey should return expected extended private key', () => { 34 | const extPrivateKey = wallet.extendedPrivateKey; 35 | expect(typeof extPrivateKey).toBe('string'); 36 | expect(extPrivateKey).toBe('xprvA2NTL1ZqHfcTbSbCXeRcuUWo9jib7TroFrQSMFyNS4YpSCs8Aqi23nPQHiQC6SVNXp68AFQLU5Nt2CEKjBmtaFhYdBTGhd7tydWxKhWzSc7'); 37 | }); 38 | 39 | test('extendedPublicKey should return expected extended public key', () => { 40 | const extPublicKey = wallet.extendedPublicKey; 41 | expect(typeof extPublicKey).toBe('string'); 42 | expect(extPublicKey).toBe('xpub6FMojX6j83AkovffdfxdGcTXhmZ5Wvaed5L39eNyzQ5oK1CGiP2Gbaht8yTEBM2rfGMpNnkkXiQkhUKJnnrc31yLgvmimYWEhXdGXwy16eW'); 43 | }); 44 | 45 | test('getAddress should return PaymentAddress instance for given index', () => { 46 | const address = wallet.getAddress(0); 47 | expect(address).toBeInstanceOf(PaymentAddress); 48 | expect(address.encoded()).toBe('bitcoincash:qr9sawzzmstkluq9nqefsu7eqya4zk2w7udune2pmf'); 49 | }); 50 | 51 | test('getAddresses should return array of PaymentAddress instances', () => { 52 | const addresses = wallet.getAddresses(5); 53 | expect(Array.isArray(addresses)).toBeTruthy(); 54 | expect(addresses).toHaveLength(5); 55 | 56 | expect(addresses.map(a => a.encoded())).toStrictEqual([ 57 | 'bitcoincash:qr9sawzzmstkluq9nqefsu7eqya4zk2w7udune2pmf', 58 | 'bitcoincash:qpvmwrhxcdyyq64ar6kz46rejp0r2tjcwg8d462hum', 59 | 'bitcoincash:qqftgwpz0wm45z3sumncfrzm0s3n7x5rcqq9350gd6', 60 | 'bitcoincash:qrwelh5dw56rjnr3nnttfc45j0p0yv2a3vtuwu9nlt', 61 | 'bitcoincash:qpawyf7fp6lhvhld5gtz74smm969fx2j2546uj60l0']) 62 | }); 63 | 64 | 65 | describe('generateAddresses generator', () => { 66 | it('should lazily generate addresses', () => { 67 | const addresses = wallet.generateAddresses(); 68 | expect(addresses.take(5).map(a => a.encoded()).toArray()).toStrictEqual([ 69 | 'bitcoincash:qr9sawzzmstkluq9nqefsu7eqya4zk2w7udune2pmf', 70 | 'bitcoincash:qpvmwrhxcdyyq64ar6kz46rejp0r2tjcwg8d462hum', 71 | 'bitcoincash:qqftgwpz0wm45z3sumncfrzm0s3n7x5rcqq9350gd6', 72 | 'bitcoincash:qrwelh5dw56rjnr3nnttfc45j0p0yv2a3vtuwu9nlt', 73 | 'bitcoincash:qpawyf7fp6lhvhld5gtz74smm969fx2j2546uj60l0' 74 | ]); 75 | }); 76 | }); 77 | 78 | 79 | // test('deriveAccount should return a new Wallet instance with new derivation path', () => { 80 | // const newDerivationPath = "m/44'/0'/0'/0"; 81 | // const derivedWallet = wallet.deriveAccount(newDerivationPath); 82 | // expect(derivedWallet).toBeInstanceOf(Wallet); 83 | // expect(derivedWallet.derivationPath).toBe(newDerivationPath); 84 | // }); 85 | }); 86 | 87 | -------------------------------------------------------------------------------- /src/wallet/wallet.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | 7 | const paymentAddress = require('./paymentAddress'); 8 | const { LazySequence } = require('../utils/lazySequence'); 9 | 10 | class Wallet { 11 | constructor(mnemonic, derivationPath, network = 'MAINNET') { 12 | if ( ! derivationPath) { 13 | throw new Error('Derivation path is required.'); 14 | } 15 | 16 | this.mnemonic = mnemonic; 17 | this.derivationPath = derivationPath; 18 | this.network = network; 19 | 20 | this._initialize(); 21 | } 22 | 23 | _initialize() { 24 | const wl = kth.core_string_list_construct(); 25 | this.mnemonic.forEach(word => { 26 | kth.core_string_list_push_back(wl, word); 27 | }); 28 | 29 | this.seed = kth.wallet_mnemonics_to_seed(wl); 30 | 31 | const version = this.network === 'MAINNET' ? 326702167824577054n : 303293221666392015n; 32 | this.master = kth.wallet_hd_private_construct_seed(this.seed, version); 33 | 34 | const paths = this.derivationPath.split('/'); 35 | this.lastDerived = paths.reduce((prevKey, pathChunk) => { 36 | if (pathChunk === 'm') { 37 | return prevKey; 38 | } 39 | const hardened = pathChunk.endsWith("'"); 40 | const index = parseInt(pathChunk, 10); 41 | if (isNaN(index)) { 42 | throw new Error('Invalid derivation path.'); 43 | } 44 | 45 | if (hardened) { 46 | return kth.wallet_hd_private_derive_private(prevKey, index + 0x80000000); 47 | } else { 48 | return kth.wallet_hd_private_derive_private(prevKey, index); 49 | } 50 | }, this.master); 51 | } 52 | 53 | get rootKey() { 54 | return kth.wallet_hd_private_encoded(this.master); 55 | } 56 | 57 | get extendedPrivateKey() { 58 | return kth.wallet_hd_private_encoded(this.lastDerived); 59 | } 60 | 61 | get extendedPublicKey() { 62 | return kth.wallet_hd_public_encoded(kth.wallet_hd_private_to_public(this.lastDerived)); 63 | } 64 | 65 | getAddress(index) { 66 | const key = kth.wallet_hd_private_derive_private(this.lastDerived, index); 67 | const secret = kth.wallet_hd_private_secret(key); 68 | const point = kth.wallet_secret_to_public(secret); 69 | const ecp = kth.wallet_ec_public_construct_from_point(point, true); 70 | const nativePA = kth.wallet_ec_public_to_payment_address(ecp, this.network === 'MAINNET' ? 0x00 : 0x05); 71 | return paymentAddress.fromNative(nativePA); 72 | } 73 | 74 | getAddresses(count = 20) { 75 | const addresses = []; 76 | for (let i = 0; i < count; i++) { 77 | addresses.push(this.getAddress(i)); 78 | } 79 | return addresses; 80 | } 81 | 82 | // *generateAddresses() { 83 | // let index = 0; 84 | // while (true) { 85 | // yield this.getAddress(index++); 86 | // } 87 | // } 88 | 89 | generateAddresses() { 90 | const self = this; 91 | return new LazySequence(function*() { 92 | let index = 0; 93 | while (true) { 94 | yield self.getAddress(index++); 95 | } 96 | }); 97 | } 98 | 99 | deriveAccount(derivationPath) { 100 | return new Wallet(this.mnemonic, derivationPath, this.network); 101 | } 102 | 103 | //TODO: Implement isValidMnemonic(mnemonic) function. 104 | //TODO: Implement generate() function. 105 | //TODO: Implement mnemonic() function. 106 | 107 | // This will return a new Wallet instance with only public info. 108 | // toPublic() { 109 | // const pubWallet = new Wallet(null, this.derivationPath, this.network); 110 | // pubWallet.master = kth.wallet_hd_private_to_public(this.master); 111 | // pubWallet.lastDerived = kth.wallet_hd_private_to_public(this.lastDerived); 112 | // return pubWallet; 113 | // } 114 | } 115 | 116 | exports.Wallet = Wallet; 117 | -------------------------------------------------------------------------------- /test/chain/genesis.txt: -------------------------------------------------------------------------------- 1 | const output = require('../src/chain/output'); 2 | const enc = require('../src/encoding'); 3 | 4 | test('construct using fromData()', () => { 5 | 6 | // Header start 7 | "01000000" // 4 8 | "0000000000000000000000000000000000000000000000000000000000000000" // 32 9 | "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a" // 32 10 | "29ab5f49" // 4 11 | "ffff001d" // 4 12 | "1dac2b7c" // 4 13 | // Header end 14 | 15 | "01" // 1 Number of transactions 16 | 17 | // Transaction start 18 | "01000000" // 4 Transaction version 19 | "01" // 1 Number of inputs 20 | // Input start 21 | "0000000000000000000000000000000000000000000000000000000000000000ffffffff" // 36 (32+4) Previous Outpoint 22 | "4d" // 1 Script size 0x4d = 77 23 | "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73" 24 | "ffffffff" // 4 sequence 25 | // Input end 26 | 27 | "01" // 1 Number of outputs 28 | // Output end 29 | "00f2052a01000000" // 8 Amount 30 | "43" // 1 Script size 0x43 = 67 31 | "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" 32 | // Output end 33 | "00000000" // 4 Sequence 34 | // Transaction end 35 | 36 | 37 | 38 | // 50 * 100'000'000 = 5'000'000'000 = 0x01 2A 05 F2 00 39 | 40 | 41 | const scriptStr = 42 | '4104f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446aac'; 43 | const outputStr = 44 | '4104f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446aac'; 45 | const outputBytes = enc.hexStrToBytes(outputStr); 46 | const h = output.fromData(1, outputBytes); 47 | expect(h.version).toBe(1); 48 | expect(h.timestamp).toBe(1231006505); 49 | expect(h.bits).toBe(0x1d00ffff); 50 | expect(h.nonce).toBe(2083236893); 51 | expect(enc.bytesToHexStr(h.rawData(1))).toBe(outputStr); 52 | }); 53 | 54 | // test('construct using main constructor', () => { 55 | // const previousBlockHash = enc.Hash.strToBytes('0000000000000000000000000000000000000000000000000000000000000000'); 56 | // const merkle = enc.Hash.strToBytes('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'); 57 | // const h = new output.Header(1, previousBlockHash, merkle, 1231006505, 0x1d00ffff, 2083236893); 58 | 59 | // expect(enc.Hash.bytesToStr(h.hash)).toBe('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'); 60 | // expect(enc.Hash.bytesToStr(h.hash)).toEqual('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'); 61 | // expect(h.version).toBe(1); 62 | // expect(enc.Hash.bytesToStr(h.previousBlockHash)).toEqual( 63 | // '0000000000000000000000000000000000000000000000000000000000000000' 64 | // ); 65 | // expect(enc.Hash.bytesToStr(h.merkle)).toEqual('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'); 66 | // expect(h.timestamp).toBe(1231006505); 67 | // expect(h.bits).toBe(0x1d00ffff); 68 | // expect(h.nonce).toBe(2083236893); 69 | // expect(enc.bytesToHexStr(h.rawData(1))).toBe( 70 | // '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c00' 71 | // ); 72 | // }); 73 | -------------------------------------------------------------------------------- /examples/subscribe_multiple.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | /* eslint-disable */ 6 | 7 | // const kth = require("@knuth/bch") 8 | const kth = require('../src/kth'); 9 | 10 | let running_ = false; 11 | 12 | let max = [1, 2, 3, 5, 7, 11, 13, 17, 19, 23]; 13 | let count = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 14 | 15 | const onBlockArrivedGenerator = (n) => { 16 | return (e, height, incomingBlocks, outgoingBlocks) => { 17 | // console.log(`onBlockArrivedGenerator ${n}: `, e, height); 18 | console.log(`onBlockArrivedGenerator - `, n, e, height); 19 | 20 | if (e !== kth.errors.success) { 21 | console.log(`Error: ${e}`); 22 | return false; 23 | } 24 | 25 | if ( ! running_) { 26 | return false; 27 | } 28 | 29 | if (incomingBlocks.length > 0) { 30 | console.log("new tip height: ", height + incomingBlocks.length); 31 | } 32 | 33 | if (n >= max.length) { 34 | console.log("n >= max.length"); 35 | return false; 36 | } 37 | 38 | count[n] += 1; 39 | if (count[n] >= max[n]) { 40 | console.log("count[n] >= max[n]"); 41 | return false; 42 | } 43 | 44 | return true; 45 | } 46 | } 47 | 48 | const onTransactionArrivedGenerator = (n) => { 49 | return (e, tx) => { 50 | console.log(`onTransactionArrivedGenerator - `, n, e, tx); 51 | 52 | if (e !== kth.errors.success) { 53 | console.log(`Error: ${e}`); 54 | return false; 55 | } 56 | 57 | if ( ! running_) { 58 | return false; 59 | } 60 | 61 | if (tx !== null) { 62 | console.log("Transaction received: ", tx); 63 | } 64 | 65 | if (n >= max.length) { 66 | console.log("n >= max.length"); 67 | return false; 68 | } 69 | 70 | count[n] += 1; 71 | if (count[n] >= max[n]) { 72 | console.log("count[n] >= max[n]"); 73 | return false; 74 | } 75 | 76 | return true; 77 | } 78 | } 79 | 80 | async function main() { 81 | process.on('SIGINT', shutdown); 82 | const config = kth.settings.getDefault(kth.network.chipnet); 83 | const node = new kth.node.Node(config, false); 84 | await node.launch(kth.startModules.all); 85 | console.log("Knuth node has been launched."); 86 | running_ = true; 87 | 88 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(0)); 89 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(1)); 90 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(2)); 91 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(3)); 92 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(4)); 93 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(5)); 94 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(6)); 95 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(7)); 96 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(8)); 97 | node.chain.subscribeBlockchain(onBlockArrivedGenerator(9)); 98 | 99 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(0)); 100 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(1)); 101 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(2)); 102 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(3)); 103 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(4)); 104 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(5)); 105 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(6)); 106 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(7)); 107 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(8)); 108 | node.chain.subscribeTransaction(onTransactionArrivedGenerator(9)); 109 | 110 | while (running_) { 111 | await sleep(1000); 112 | } 113 | 114 | console.log("Shutting down ..."); 115 | 116 | node.close(); 117 | console.log("Good bye!"); 118 | } 119 | 120 | function shutdown() { 121 | console.log('Graceful shutdown ...'); 122 | running_ = false; 123 | } 124 | 125 | function sleep(ms) { 126 | return new Promise((r) => setTimeout(r, ms)); 127 | } 128 | 129 | (async () => { 130 | try { 131 | await main(); 132 | } catch (e) { 133 | console.log(e); 134 | } 135 | })(); 136 | -------------------------------------------------------------------------------- /src/wallet/paymentAddress.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const kth = require('@knuth/bch-native'); 6 | const memoize = require('memoizee'); 7 | const result = require('../result'); 8 | 9 | class PaymentAddress { 10 | constructor(addressStr, tokenAware = false, legacy = false) { 11 | this.addressStr = addressStr; 12 | this.tokenAware = tokenAware; 13 | this.legacy = legacy; 14 | } 15 | 16 | toNative() { 17 | const native = kth.wallet_payment_address_construct_from_string(this.addressStr); 18 | return native; 19 | } 20 | 21 | get hash() { 22 | const res = memoizedHash(this); 23 | return res; 24 | } 25 | 26 | get version() { 27 | const res = memoizedVersion(this); 28 | return res; 29 | } 30 | 31 | encoded() { 32 | if (this.tokenAware) { 33 | const res = memoizedEncoded(this, false); 34 | return res; 35 | } 36 | return this.addressStr; 37 | } 38 | 39 | // This is an alias for encoded() 40 | encodedCashAddr() { 41 | const res = memoizedEncoded(this, false); 42 | return res; 43 | } 44 | 45 | encodedCashTokens() { 46 | const res = memoizedEncoded(this, true); 47 | return res; 48 | } 49 | 50 | encodedLegacy() { 51 | const res = memoizedEncodedLegacy(this); 52 | return res; 53 | } 54 | } 55 | 56 | const fromNative = (native, destroy = false) => { 57 | const obj = new PaymentAddress(kth.wallet_payment_address_encoded_cashaddr(native, false), false, false); 58 | if (destroy) { 59 | destruct(native); 60 | } 61 | return obj; 62 | }; 63 | 64 | const fromNativeCashTokens = (native, destroy = false) => { 65 | const obj = new PaymentAddress(kth.wallet_payment_address_encoded_cashaddr(native, true), true, false); 66 | if (destroy) { 67 | destruct(native); 68 | } 69 | return obj; 70 | }; 71 | 72 | const fromNativeLegacy = (native, destroy = false) => { 73 | const obj = new PaymentAddress(kth.wallet_payment_address_encoded_legacy(native), false, true); 74 | if (destroy) { 75 | destruct(native); 76 | } 77 | return obj; 78 | }; 79 | 80 | const fromString = (addressStr) => { 81 | const native = kth.wallet_payment_address_construct_from_string(addressStr); 82 | const valid = kth.wallet_payment_address_is_valid(native); 83 | if (!valid) { 84 | destruct(native); 85 | return new result.Result(undefined, false); 86 | } 87 | const obj = fromNative(native); 88 | destruct(native); 89 | return new result.Result(obj, true); 90 | }; 91 | 92 | const fromStringCashTokens = (addressStr) => { 93 | const native = kth.wallet_payment_address_construct_from_string(addressStr); 94 | const valid = kth.wallet_payment_address_is_valid(native); 95 | if (!valid) { 96 | destruct(native); 97 | return new result.Result(undefined, false); 98 | } 99 | const obj = fromNativeCashTokens(native); 100 | destruct(native); 101 | return new result.Result(obj, true); 102 | }; 103 | 104 | const fromStringLegacy = (addressStr) => { 105 | const native = kth.wallet_payment_address_construct_from_string(addressStr); 106 | const valid = kth.wallet_payment_address_is_valid(native); 107 | if (!valid) { 108 | destruct(native); 109 | return new result.Result(undefined, false); 110 | } 111 | const obj = fromNativeLegacy(native); 112 | destruct(native); 113 | return new result.Result(obj, true); 114 | }; 115 | 116 | const isValid = (addressStr) => { 117 | const native = kth.wallet_payment_address_construct_from_string(addressStr); 118 | const valid = kth.wallet_payment_address_is_valid(native); 119 | destruct(native); 120 | return valid; 121 | }; 122 | 123 | const encodedLegacy = (obj) => { 124 | const native = obj.toNative(); 125 | const res = kth.wallet_payment_address_encoded_legacy(native); 126 | destruct(native); 127 | return res; 128 | }; 129 | 130 | const encoded = (obj, tokenAware) => { 131 | const native = obj.toNative(); 132 | const res = kth.wallet_payment_address_encoded_cashaddr(native, tokenAware); 133 | destruct(native); 134 | return res; 135 | }; 136 | 137 | const hash = (obj) => { 138 | const native = obj.toNative(); 139 | const res = kth.wallet_payment_address_hash(native); 140 | destruct(native); 141 | return res; 142 | }; 143 | 144 | const version = (obj) => { 145 | const native = obj.toNative(); 146 | const res = kth.wallet_payment_address_version(native); 147 | destruct(native); 148 | return res; 149 | }; 150 | 151 | const memoizedEncoded = memoize(encoded); 152 | const memoizedEncodedLegacy = memoize(encodedLegacy); 153 | const memoizedHash = memoize(hash); 154 | const memoizedVersion = memoize(version); 155 | 156 | const destruct = (native) => { 157 | kth.wallet_payment_address_destruct(native); 158 | }; 159 | 160 | exports.fromNative = fromNative; 161 | exports.fromNativeCashTokens = fromNativeCashTokens; 162 | exports.fromNativeLegacy = fromNativeLegacy; 163 | 164 | exports.fromString = fromString; 165 | exports.fromStringCashTokens = fromStringCashTokens; 166 | exports.fromStringLegacy = fromStringLegacy; 167 | 168 | exports.isValid = isValid; 169 | exports.destruct = destruct; 170 | exports.PaymentAddress = PaymentAddress; 171 | -------------------------------------------------------------------------------- /test/chain/transaction.test.js: -------------------------------------------------------------------------------- 1 | const enc = require('../../src/encoding'); 2 | const input = require('../../src/chain/input'); 3 | const num = require('../../src/numerics'); 4 | const output = require('../../src/chain/output'); 5 | const outputPoint = require('../../src/chain/outputPoint'); 6 | const script = require('../../src/chain/script'); 7 | const transaction = require('../../src/chain/transaction'); 8 | 9 | test('construct using fromData()', () => { 10 | const genesisStr = 11 | '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; 12 | const genesisBytes = enc.hexStrToBytes(genesisStr); 13 | const result = transaction.fromData(1, genesisBytes); 14 | expect(result.ok).toBe(true); 15 | 16 | const tx = result.obj; 17 | 18 | const hashStr = enc.Hash.bytesToStr(tx.hash); 19 | expect(hashStr).toBe('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'); 20 | expect(enc.fix(tx.hash)).toEqual( 21 | enc.Hash.strToBytes('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b') 22 | ); 23 | 24 | expect(tx.version).toBe(1); 25 | expect(tx.locktime).toBe(0); 26 | expect(tx.inputs.length).toBe(1); 27 | expect(tx.outputs.length).toBe(1); 28 | 29 | const inputScriptStr = 30 | '04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73'; 31 | const inputStr = 32 | '0000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff'; 33 | const i = tx.inputs[0]; 34 | expect(i.previousOutpoint.index).toBe(0xffffffff); 35 | expect(enc.Hash.bytesToStr(i.previousOutpoint.hash)).toBe( 36 | '0000000000000000000000000000000000000000000000000000000000000000' 37 | ); 38 | expect(enc.bytesToHexStr(i.script.rawData())).toBe(inputScriptStr); 39 | expect(enc.bytesToHexStr(i.rawData())).toBe(inputStr); 40 | expect(i.sequence).toBe(0xffffffff); 41 | 42 | const outputScriptStr = 43 | '4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac'; 44 | const outputStr = 45 | '00f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac'; 46 | const o = tx.outputs[0]; 47 | expect(o.value).toBe(num.toSatoshis(50)); 48 | expect(enc.bytesToHexStr(o.script.rawData())).toBe(outputScriptStr); 49 | expect(enc.bytesToHexStr(o.rawData())).toBe(outputStr); 50 | 51 | expect(enc.bytesToHexStr(tx.rawData())).toBe(genesisStr); 52 | }); 53 | 54 | test('construct using main constructor', () => { 55 | const inputScriptStr = 56 | '04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73'; 57 | const inputScriptBytes = enc.hexStrToBytes(inputScriptStr); 58 | let result = script.fromData(inputScriptBytes, false); 59 | expect(result.ok).toBe(true); 60 | const inputScript = result.obj; 61 | const previousOutpoint = new outputPoint.OutputPoint(enc.Hash.nullHash(), 0xffffffff); 62 | const inputs = [new input.Input(previousOutpoint, inputScript, 0xffffffff)]; 63 | 64 | const outputScriptStr = 65 | '4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac'; 66 | const outputScriptBytes = enc.hexStrToBytes(outputScriptStr); 67 | result = script.fromData(outputScriptBytes, false); 68 | expect(result.ok).toBe(true); 69 | const outputScript = result.obj; 70 | const outputs = [new output.Output(num.toSatoshis(50), outputScript)]; 71 | const tx = new transaction.Transaction(1, 0, inputs, outputs); 72 | 73 | const hashStr = enc.Hash.bytesToStr(tx.hash); 74 | expect(hashStr).toBe('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'); 75 | expect(enc.fix(tx.hash)).toEqual( 76 | enc.Hash.strToBytes('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b') 77 | ); 78 | 79 | expect(tx.version).toBe(1); 80 | expect(tx.locktime).toBe(0); 81 | expect(tx.inputs.length).toBe(1); 82 | expect(tx.outputs.length).toBe(1); 83 | 84 | const genesisStr = 85 | '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; 86 | 87 | const inputStr = 88 | '0000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff'; 89 | const i = tx.inputs[0]; 90 | expect(i.previousOutpoint.index).toBe(0xffffffff); 91 | expect(enc.Hash.bytesToStr(i.previousOutpoint.hash)).toBe( 92 | '0000000000000000000000000000000000000000000000000000000000000000' 93 | ); 94 | expect(enc.bytesToHexStr(i.script.rawData())).toBe(inputScriptStr); 95 | expect(enc.bytesToHexStr(i.rawData())).toBe(inputStr); 96 | expect(i.sequence).toBe(0xffffffff); 97 | 98 | const outputStr = 99 | '00f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac'; 100 | const o = tx.outputs[0]; 101 | expect(o.value).toBe(num.toSatoshis(50)); 102 | expect(enc.bytesToHexStr(o.script.rawData())).toBe(outputScriptStr); 103 | expect(enc.bytesToHexStr(o.rawData())).toBe(outputStr); 104 | 105 | expect(enc.bytesToHexStr(tx.rawData())).toBe(genesisStr); 106 | }); 107 | -------------------------------------------------------------------------------- /test/config/blockchainSettings.test.js: -------------------------------------------------------------------------------- 1 | const blockchainSettings = require('../../src/config/blockchainSettings'); 2 | const network = require('../../src/config/network'); 3 | const enc = require('../../src/encoding'); 4 | 5 | test('read default mainnet settings', () => { 6 | const settings = blockchainSettings.getDefault(network.Network.mainnet); 7 | expect(settings.cores).toBe(0); 8 | expect(settings.priority).toBe(true); 9 | 10 | expect(settings.byteFeeSatoshis).toBeCloseTo(0.1); 11 | expect(settings.sigopFeeSatoshis).toBe(100.0); 12 | expect(settings.minimumOutputSatoshis).toBe(500); 13 | expect(settings.notifyLimitHours).toBe(24); 14 | expect(settings.reorganizationLimit).toBe(256); 15 | 16 | expect(settings.checkpoints.length).toBe(79); 17 | expect(settings.checkpoints[0].height).toBe(0); 18 | expect(enc.Hash.bytesToStr(settings.checkpoints[0].hash)).toBe( 19 | '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f' 20 | ); 21 | 22 | expect(settings.fixCheckpoints).toBe(true); 23 | expect(settings.allowCollisions).toBe(true); 24 | expect(settings.easyBlocks).toBe(false); 25 | expect(settings.retarget).toBe(true); 26 | expect(settings.bip16).toBe(true); 27 | expect(settings.bip30).toBe(true); 28 | expect(settings.bip34).toBe(true); 29 | expect(settings.bip66).toBe(true); 30 | expect(settings.bip65).toBe(true); 31 | expect(settings.bip90).toBe(true); 32 | expect(settings.bip68).toBe(true); 33 | expect(settings.bip112).toBe(true); 34 | expect(settings.bip113).toBe(true); 35 | expect(settings.bchUahf).toBe(true); 36 | expect(settings.bchDaaCw144).toBe(true); 37 | expect(settings.bchPythagoras).toBe(true); 38 | expect(settings.bchEuclid).toBe(true); 39 | expect(settings.bchPisano).toBe(true); 40 | expect(settings.bchMersenne).toBe(true); 41 | expect(settings.bchFermat).toBe(true); 42 | expect(settings.bchEuler).toBe(true); 43 | expect(settings.bchGauss).toBe(true); 44 | expect(settings.bchDescartes).toBe(true); 45 | expect(settings.bchLobachevski).toBe(true); 46 | 47 | expect(settings.galoisActivationTime).toBe(1747310400); 48 | expect(settings.leibnizActivationTime).toBe(1778846400); 49 | 50 | expect(settings.asertHalfLife).toBe(2 * 24 * 60 * 60); //two days 51 | }); 52 | 53 | test('read default testnet4 settings', () => { 54 | const settings = blockchainSettings.getDefault(network.Network.testnet4); 55 | expect(settings.cores).toBe(0); 56 | expect(settings.priority).toBe(true); 57 | 58 | expect(settings.byteFeeSatoshis).toBeCloseTo(0.1); 59 | expect(settings.sigopFeeSatoshis).toBe(100.0); 60 | expect(settings.minimumOutputSatoshis).toBe(500); 61 | expect(settings.notifyLimitHours).toBe(24); 62 | expect(settings.reorganizationLimit).toBe(256); 63 | 64 | expect(settings.checkpoints.length).toBe(18); 65 | expect(settings.checkpoints[0].height).toBe(0); 66 | expect(enc.Hash.bytesToStr(settings.checkpoints[0].hash)).toBe( 67 | '000000001dd410c49a788668ce26751718cc797474d3152a5fc073dd44fd9f7b' 68 | ); 69 | 70 | expect(settings.fixCheckpoints).toBe(true); 71 | expect(settings.allowCollisions).toBe(true); 72 | expect(settings.easyBlocks).toBe(true); 73 | expect(settings.retarget).toBe(true); 74 | expect(settings.bip16).toBe(true); 75 | expect(settings.bip30).toBe(true); 76 | expect(settings.bip34).toBe(true); 77 | expect(settings.bip66).toBe(true); 78 | expect(settings.bip65).toBe(true); 79 | expect(settings.bip90).toBe(true); 80 | expect(settings.bip68).toBe(true); 81 | expect(settings.bip112).toBe(true); 82 | expect(settings.bip113).toBe(true); 83 | expect(settings.bchUahf).toBe(true); 84 | expect(settings.bchDaaCw144).toBe(true); 85 | expect(settings.bchPythagoras).toBe(true); 86 | expect(settings.bchEuclid).toBe(true); 87 | expect(settings.bchPisano).toBe(true); 88 | expect(settings.bchMersenne).toBe(true); 89 | expect(settings.bchFermat).toBe(true); 90 | expect(settings.bchEuler).toBe(true); 91 | expect(settings.bchGauss).toBe(true); 92 | expect(settings.bchDescartes).toBe(true); 93 | expect(settings.bchLobachevski).toBe(true); 94 | 95 | expect(settings.galoisActivationTime).toBe(1747310400); 96 | expect(settings.leibnizActivationTime).toBe(1778846400); 97 | 98 | expect(settings.asertHalfLife).toBe(60 * 60); //one hour 99 | }); 100 | 101 | test('read default chipnet settings', () => { 102 | const settings = blockchainSettings.getDefault(network.Network.chipnet); 103 | expect(settings.cores).toBe(0); 104 | expect(settings.priority).toBe(true); 105 | 106 | expect(settings.byteFeeSatoshis).toBeCloseTo(0.1); 107 | expect(settings.sigopFeeSatoshis).toBe(100.0); 108 | expect(settings.minimumOutputSatoshis).toBe(500); 109 | expect(settings.notifyLimitHours).toBe(24); 110 | expect(settings.reorganizationLimit).toBe(256); 111 | 112 | expect(settings.checkpoints.length).toBe(14); 113 | expect(settings.checkpoints[0].height).toBe(0); 114 | expect(enc.Hash.bytesToStr(settings.checkpoints[0].hash)).toBe( 115 | '000000001dd410c49a788668ce26751718cc797474d3152a5fc073dd44fd9f7b' 116 | ); 117 | 118 | expect(settings.fixCheckpoints).toBe(true); 119 | expect(settings.allowCollisions).toBe(true); 120 | expect(settings.easyBlocks).toBe(true); 121 | expect(settings.retarget).toBe(true); 122 | expect(settings.bip16).toBe(true); 123 | expect(settings.bip30).toBe(true); 124 | expect(settings.bip34).toBe(true); 125 | expect(settings.bip66).toBe(true); 126 | expect(settings.bip65).toBe(true); 127 | expect(settings.bip90).toBe(true); 128 | expect(settings.bip68).toBe(true); 129 | expect(settings.bip112).toBe(true); 130 | expect(settings.bip113).toBe(true); 131 | expect(settings.bchUahf).toBe(true); 132 | expect(settings.bchDaaCw144).toBe(true); 133 | expect(settings.bchPythagoras).toBe(true); 134 | expect(settings.bchEuclid).toBe(true); 135 | expect(settings.bchPisano).toBe(true); 136 | expect(settings.bchMersenne).toBe(true); 137 | expect(settings.bchFermat).toBe(true); 138 | expect(settings.bchEuler).toBe(true); 139 | expect(settings.bchGauss).toBe(true); 140 | expect(settings.bchDescartes).toBe(true); 141 | expect(settings.bchLobachevski).toBe(true); 142 | 143 | expect(settings.galoisActivationTime).toBe(1747310400); 144 | expect(settings.leibnizActivationTime).toBe(1778846400); 145 | 146 | expect(settings.asertHalfLife).toBe(60 * 60); //one hour 147 | }); 148 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-2024 Knuth Project developers. 2 | # Distributed under the MIT software license, see the accompanying 3 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | name: Build and Test 6 | 7 | on: [push, pull_request] 8 | 9 | # on: 10 | # release: 11 | # types: [created] 12 | 13 | jobs: 14 | # execute-linter: 15 | # name: Execute ESLint 16 | # runs-on: ubuntu-latest 17 | # steps: 18 | # - uses: actions/checkout@v3 19 | # - uses: actions/setup-node@v3 20 | # with: 21 | # node-version: 16 22 | # - name: Install modules 23 | # run: npm install 24 | # # - name: Run ESLint 25 | # # run: npm run lint:github-action 26 | 27 | generate-matrix: 28 | # needs: execute-linter 29 | name: Generate Job Matrix 30 | # if: github.ref == 'refs/heads/master' 31 | runs-on: ubuntu-latest 32 | outputs: 33 | matrix: ${{ steps.set-matrix.outputs.matrix }} 34 | steps: 35 | - name: Generate Job Matrix 36 | id: set-matrix 37 | env: 38 | MATRIX: '{"config": [ 39 | {"name": "macOS 14 (ARM) - NodeJS 20","nodejs_version": "20","os": "macos-14","os_kind": "macos", "os_version": "14.0","test": "0"} 40 | ]}' 41 | 42 | run: | 43 | echo "${MATRIX}" 44 | echo "matrix=${MATRIX}" >> $GITHUB_OUTPUT 45 | 46 | builds: 47 | needs: generate-matrix 48 | runs-on: ${{ matrix.config.os }} 49 | strategy: 50 | fail-fast: false 51 | matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}} 52 | name: ${{ matrix.config.name }} 53 | steps: 54 | - uses: actions/checkout@v3 55 | - uses: actions/setup-node@v3 56 | with: 57 | node-version: ${{ matrix.config.nodejs_version }} 58 | - uses: actions/setup-python@v4 59 | with: 60 | python-version: "3.11" 61 | 62 | - name: Settting EnvVars (macOS) 63 | if: ${{ matrix.config.os_kind == 'macos' }} 64 | shell: bash 65 | run: | 66 | echo "MACOSX_DEPLOYMENT_TARGET=${{ matrix.config.os_version }}" >> $GITHUB_ENV 67 | 68 | # - name: Settting EnvVars (Unix) 69 | # if: ${{ matrix.config.os_kind != 'windows' }} 70 | # shell: bash 71 | # run: | 72 | # echo "NODEJS_VERSION=${{ matrix.config.nodejs_version }}" >> $GITHUB_ENV 73 | # echo "KTH_GHA_MARCH_ID=${{ matrix.config.march_id }}" >> $GITHUB_ENV 74 | # echo "KTH_GHA_RUN_TESTS=${{ matrix.config.test }}" >> $GITHUB_ENV 75 | 76 | # - name: Settting EnvVars (Windows) 77 | # if: ${{ matrix.config.os_kind == 'windows' }} 78 | # shell: powershell 79 | # run: | 80 | # echo "NODEJS_VERSION=${{ matrix.config.nodejs_version }}" >> $Env:GITHUB_ENV 81 | # echo "KTH_GHA_MARCH_ID=${{ matrix.config.march_id }}" >> $Env:GITHUB_ENV 82 | # echo "KTH_GHA_RUN_TESTS=${{ matrix.config.test }}" >> $Env:GITHUB_ENV 83 | 84 | - run: python --version 85 | - run: python3 --version 86 | - run: clang --version 87 | # - run: npm install --loglevel verbose 88 | - run: npm install 89 | # - run: npm run lint:github-action 90 | - run: git status 91 | - run: git diff 92 | - run: npm ci 93 | # - run: npm test --runInBand 94 | - run: npm test -- --verbose=true 95 | if: ${{ matrix.config.test == '1' }} 96 | 97 | publish-npm: 98 | needs: builds 99 | runs-on: ubuntu-latest 100 | name: Public NPM 101 | steps: 102 | - uses: actions/checkout@v3 103 | - uses: actions/setup-node@v3 104 | with: 105 | node-version: 20 106 | registry-url: https://registry.npmjs.org/ 107 | - run: npm ci 108 | - run: npm publish --access public 109 | env: 110 | NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} 111 | 112 | # publish: 113 | # runs-on: ubuntu-latest 114 | # steps: 115 | # - uses: actions/checkout@v3 116 | # # Setup .npmrc file to publish to npm 117 | # - uses: actions/setup-node@v3 118 | # with: 119 | # node-version: 16 120 | # registry-url: 'https://registry.npmjs.org' 121 | # - run: npm install 122 | # # Publish to npm 123 | # - run: npm publish --access public 124 | # env: 125 | # NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 126 | # # Setup .npmrc file to publish to GitHub Packages 127 | # - uses: actions/setup-node@v3 128 | # with: 129 | # registry-url: 'https://npm.pkg.github.com' 130 | # # Defaults to the user or organization that owns the workflow file 131 | # scope: '@octocat' 132 | # # Publish to GitHub Packages 133 | # - run: npm publish 134 | # env: 135 | # NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 136 | 137 | # publish-npm: 138 | # needs: builds 139 | # runs-on: ubuntu-latest 140 | # name: Public NPM 141 | # steps: 142 | # - uses: actions/checkout@v3 143 | # - uses: actions/setup-node@v3 144 | # with: 145 | # node-version: 16 146 | # - run: npm install 147 | # - run: npm test 148 | # # - run: npm ci 149 | # - uses: JS-DevTools/npm-publish@v1 150 | # with: 151 | # token: ${{ secrets.NPM_AUTH_TOKEN }} 152 | # registry: https://registry.npmjs.org/ 153 | 154 | # publish-gpr: 155 | # needs: builds 156 | # runs-on: ubuntu-latest 157 | # name: Public GPR 158 | # steps: 159 | # - uses: actions/checkout@v3 160 | # - uses: actions/setup-node@v3 161 | # with: 162 | # node-version: 16 163 | # - run: npm install 164 | # # - run: npm test 165 | # # - run: npm ci 166 | # - uses: JS-DevTools/npm-publish@v1 167 | # with: 168 | # token: ${{ secrets.GITHUB_TOKEN }} 169 | # registry: https://npm.pkg.github.com/ 170 | 171 | # publish-npm: 172 | # needs: builds 173 | # runs-on: ubuntu-latest 174 | # name: Public NPM 175 | # steps: 176 | # - uses: actions/checkout@v3 177 | # - uses: actions/setup-node@v3 178 | # with: 179 | # node-version: 16 180 | # registry-url: https://registry.npmjs.org/ 181 | # - run: npm ci 182 | # - run: npm publish 183 | # env: 184 | # NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} 185 | 186 | # publish-gpr: 187 | # # needs: publish-npm 188 | # needs: builds 189 | # runs-on: ubuntu-latest 190 | # name: Public GPR 191 | # steps: 192 | # - uses: actions/checkout@v3 193 | # - uses: actions/setup-node@v3 194 | # with: 195 | # node-version: 16 196 | # registry-url: https://npm.pkg.github.com/ 197 | # # - run: npm login 198 | # # - run: npm ci 199 | # - run: npm ci 200 | # - run: npm publish 201 | # env: 202 | # NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /test/chain/block.test.js: -------------------------------------------------------------------------------- 1 | const block = require('../../src/chain/block'); 2 | const enc = require('../../src/encoding'); 3 | const header = require('../../src/chain/header'); 4 | const transaction = require('../../src/chain/transaction'); 5 | 6 | test('construct using fromData()', () => { 7 | const genesisStr = 8 | '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; 9 | const genesisBytes = enc.hexStrToBytes(genesisStr); 10 | const result = block.fromData(1, genesisBytes); 11 | expect(result.ok).toBe(true); 12 | 13 | const blk = result.obj; 14 | 15 | const hashStr = enc.Hash.bytesToStr(blk.hash); 16 | expect(hashStr).toBe('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'); 17 | expect(enc.fix(blk.hash)).toEqual( 18 | enc.Hash.strToBytes('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f') 19 | ); 20 | 21 | expect(blk.header.version).toBe(1); 22 | expect(enc.fix(blk.header.previousBlockHash)).toEqual(enc.Hash.nullHash()); 23 | expect(enc.fix(blk.header.merkle)).toEqual( 24 | enc.Hash.strToBytes('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b') 25 | ); 26 | expect(blk.header.timestamp).toBe(1231006505); 27 | expect(blk.header.bits).toBe(0x1d00ffff); 28 | expect(blk.header.nonce).toBe(2083236893); 29 | 30 | expect(blk.transactions.length).toBe(1); 31 | 32 | const tx = blk.transactions[0]; 33 | expect(tx.version).toBe(1); 34 | expect(tx.locktime).toBe(0); 35 | expect(tx.inputs.length).toBe(1); 36 | expect(tx.outputs.length).toBe(1); 37 | expect(tx.inputs.length).toBe(1); 38 | expect(tx.outputs.length).toBe(1); 39 | expect(enc.Hash.bytesToStr(tx.hash)).toBe('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'); 40 | const transactionStr = 41 | '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; 42 | expect(enc.bytesToHexStr(tx.rawData())).toBe(transactionStr); 43 | 44 | expect(enc.bytesToHexStr(blk.rawData())).toBe(genesisStr); 45 | }); 46 | 47 | test('construct using main constructor', () => { 48 | const headerStr = 49 | '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c00'; 50 | const headerBytes = enc.hexStrToBytes(headerStr); 51 | let result = header.fromData(1, headerBytes); 52 | expect(result.ok).toBe(true); 53 | const head = result.obj; 54 | 55 | const trasactionStr = 56 | '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; 57 | const trasactionBytes = enc.hexStrToBytes(trasactionStr); 58 | result = transaction.fromData(1, trasactionBytes); 59 | expect(result.ok).toBe(true); 60 | 61 | const transactions = [result.obj]; 62 | 63 | const blk = new block.Block(head, transactions); 64 | 65 | const hashStr = enc.Hash.bytesToStr(blk.hash); 66 | expect(hashStr).toBe('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'); 67 | expect(enc.fix(blk.hash)).toEqual( 68 | enc.Hash.strToBytes('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f') 69 | ); 70 | 71 | expect(blk.header.version).toBe(1); 72 | expect(enc.fix(blk.header.previousBlockHash)).toEqual(enc.Hash.nullHash()); 73 | expect(enc.fix(blk.header.merkle)).toEqual( 74 | enc.Hash.strToBytes('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b') 75 | ); 76 | expect(blk.header.timestamp).toBe(1231006505); 77 | expect(blk.header.bits).toBe(0x1d00ffff); 78 | expect(blk.header.nonce).toBe(2083236893); 79 | 80 | expect(blk.transactions.length).toBe(1); 81 | 82 | const tx = blk.transactions[0]; 83 | expect(tx.version).toBe(1); 84 | expect(tx.locktime).toBe(0); 85 | expect(tx.inputs.length).toBe(1); 86 | expect(tx.outputs.length).toBe(1); 87 | expect(tx.inputs.length).toBe(1); 88 | expect(tx.outputs.length).toBe(1); 89 | expect(enc.Hash.bytesToStr(tx.hash)).toBe('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'); 90 | const transactionStr = 91 | '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; 92 | expect(enc.bytesToHexStr(tx.rawData())).toBe(transactionStr); 93 | 94 | const genesisStr = 95 | '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; 96 | expect(enc.bytesToHexStr(blk.rawData())).toBe(genesisStr); 97 | }); 98 | 99 | // public void CreateBlockFromHex', async () => { 100 | // const hex = "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"; 101 | // Block b = new Block(1, hex)) { 102 | // expect().toBeTruthy(b.IsValid); 103 | // } 104 | // } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Javascript/Typescript API 2 | 3 | > Bitcoin Cash full node as a Javascript/Typescript library 4 | 5 | [![NPM Version](https://img.shields.io/npm/v/@knuth/bch?logo=npm&style=for-the-badge)](https://www.npmjs.com/package/@knuth/bch) 6 | [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=for-the-badge&logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAHYcAAB2HAY%2Fl8WUAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTCtCgrAAAADB0lEQVR4XtWagXETMRREUwIlUAIlUAodQAl0AJ1AB9BB6AA6gA6MduKbkX%2BevKecNk525jHO3l%2Fp686xlJC70%2Bl0C942vjV%2Bn9FreVQbBc0wWujfRpW8Z78JaIb53hhJ1ygTA80w9PQ36duBMjHQHPCuoQZfutSjeqU1PAJN4E3j2pN7aVKv6pnWcgGawNfGa5N6prVcgGZBn8yvVXZXQbOgPXokXaPMNZwoc41D%2FaHZ8b7hpBrKjnCizIjD%2FaHZ8aPR6%2BeZXqqh7Agnyow43B%2BaZz40qnQ36a6rlsYgnChDLOkPzTN1z%2B9PafU0N3OAcaIMsaQ%2FNBufG1X9JyrtDMr0Y4xwokxlWX%2BPjAYdemhPrWeDvYcPJ8r0LO3v4oszNfivQQuTp2u9qJGKE2V6lvZ38UVj9q3t3oqEE2U2lvfXF4t6qPjTqDUV1fRyhw8nymws768vfOr2NtqOqFY4UUZE%2BusL6VDRX7%2FGzOHDiTIi0t9WMPsUKzNPx4kysf62gmuHir3sPXw4USbWny485ZOc2PsJ7VTro%2F3pwp5DxV7qHq2xa41TrY%2F2J7PfJkaHir3UwwdtU061PtqfTP0CUaYm2v3LxCtoDI2lMWk8p1of7Y8K0jhRJgaaYZwoE0P%2FpFUndZqtP6T4BE2zC5qtP6T4BE2zC5qtPyRN8OvhZUQae3ZBtT7anyb49PA6Ivp5wKnWR%2FvbJkncZXr6wokysf62CXRCWjmJxhqd2JwoE%2BuvTqS37JGJlB39GLzhRJmN5f31gz8XTpSJgWYYJ8rEQDOME2VioBnGiTIx0AzjRJkYaIZxokwMNMM4USYGmmGcKBMDzTBOlImBZhgnysRAM4wTZWKgGcaJMjHQDONEmRhohnGiTAw0wzhRJgaaYZwoEwPNME6UiYFmGCfKxEAzjBNlYqAZxokyMdAMoL%2FO%2BNi4bzjpT1e%2BNFb8V7gFzUXMLHqk%2BM1A8wArFj1S5GagOUly0SMtuxloTnJrUU%2B7QXOSW4t62g2ak9xa1NNu0Jzk1qKednK6%2Bw9roIB8keT%2F3QAAAABJRU5ErkJggg%3D%3D)](LICENSE.md) 7 | [![js-standard-style](https://img.shields.io/badge/javascript-standard%20code%20style-green.svg?style=for-the-badge)](https://github.com/feross/standard) 8 | ![Telegram][badge.telegram] 9 | 10 |

11 | 12 | [Knuth Javascript/Typescript API](https://www.npmjs.com/package/@knuth/bch) is a high performance implementation of the Bitcoin Cash protocol focused on users requiring extra performance and flexibility. It is a Bitcoin Cash node you can use as a library. 13 | 14 | ## Getting started with Javascript 15 | 16 | 1. Create a new Javascript console project: 17 | ``` 18 | $ mkdir HelloKnuth 19 | $ cd HelloKnuth 20 | $ npm init 21 | ``` 22 | 23 | 2. Add a reference to our Javascript API package: 24 | 25 | ``` 26 | $ npm install @knuth/bch 27 | ``` 28 | 29 | 3. Create a new file called `index.js` and write some code: 30 | 31 | ```Javascript 32 | const kth = require("@knuth/bch") 33 | 34 | let running_ = false; 35 | 36 | async function main() { 37 | process.on('SIGINT', shutdown); 38 | const config = kth.settings.getDefault(kth.network.mainnet); 39 | const node = new kth.node.Node(config, false); 40 | await node.launch(kth.startModules.all); 41 | console.log("Knuth node has been launched."); 42 | running_ = true; 43 | 44 | const [_, height] = await node.chain.getLastHeight(); 45 | console.log(`Current height in local copy: ${height}`); 46 | 47 | if (await comeBackAfterTheBCHHardFork(node)) { 48 | console.log("Bitcoin Cash has been created!"); 49 | } 50 | 51 | node.close(); 52 | console.log("Good bye!"); 53 | } 54 | 55 | async function comeBackAfterTheBCHHardFork(node) { 56 | const hfHeight = 478559; 57 | while (running_) { 58 | const [_, height] = await node.chain.getLastHeight(); 59 | if (height >= hfHeight) return true; 60 | await sleep(10000); 61 | } 62 | return false; 63 | } 64 | 65 | function shutdown() { 66 | console.log('Graceful shutdown ...'); 67 | running_ = false; 68 | } 69 | 70 | function sleep(ms) { 71 | return new Promise((r) => setTimeout(r, ms)); 72 | } 73 | 74 | (async () => { 75 | try { 76 | await main(); 77 | } catch (e) { 78 | console.log(e); 79 | } 80 | })(); 81 | 82 | ``` 83 | 84 | 4. Enjoy Knuth node as a Javascript library: 85 | 86 | ``` 87 | $ node index.js 88 | ``` 89 | 90 | ## Getting started with Typescript 91 | 92 | 1. Create a new Typescript console project: 93 | ``` 94 | $ mkdir HelloKnuth 95 | $ cd HelloKnuth 96 | $ npm init 97 | ``` 98 | 99 | 2. Add a reference to our Typescript API package and TypeScript definitions for Node.js: 100 | 101 | ``` 102 | $ npm install @knuth/bch 103 | $ npm install @types/node 104 | 105 | ``` 106 | 107 | 3. Create a new file called `index.ts` and write some code: 108 | 109 | ```Typescript 110 | import * as kth from "@knuth/bch"; 111 | 112 | let running_ = false; 113 | 114 | async function main() { 115 | process.on('SIGINT', shutdown); 116 | const config = kth.settings.getDefault(kth.network.mainnet); 117 | const node = new kth.node.Node(config, false); 118 | await node.launch(kth.startModules.all); 119 | console.log("Knuth node has been launched."); 120 | running_ = true; 121 | 122 | const [_, height] = await node.chain.getLastHeight(); 123 | console.log(`Current height in local copy: ${height}`); 124 | 125 | if (await comeBackAfterTheBCHHardFork(node)) { 126 | console.log("Bitcoin Cash has been created!"); 127 | } 128 | 129 | node.close(); 130 | console.log("Good bye!"); 131 | } 132 | 133 | async function comeBackAfterTheBCHHardFork(node : kth.node.Node) { 134 | const hfHeight = 478559; 135 | while (running_) { 136 | const [_, height] = await node.chain.getLastHeight(); 137 | if (height >= hfHeight) return true; 138 | await sleep(10000); 139 | } 140 | return false; 141 | } 142 | 143 | function shutdown() { 144 | console.log('Graceful shutdown ...'); 145 | running_ = false; 146 | } 147 | 148 | function sleep(ms : number) { 149 | return new Promise((r) => setTimeout(r, ms)); 150 | } 151 | 152 | (async () => { 153 | try { 154 | await main(); 155 | } catch (e) { 156 | console.log(e); 157 | } 158 | })(); 159 | 160 | ``` 161 | 162 | 4. Enjoy Knuth node as a Typescript library: 163 | 164 | ``` 165 | $ ts-node index.ts 166 | ``` 167 | 168 | ## Issues 169 | 170 | Each of our modules has its own Github repository, but in case you want to create an issue, please do so in our [main repository](https://github.com/k-nuth/kth/issues). 171 | 172 | 173 | 174 | [badge.Travis]: https://travis-ci.org/k-nuth/js-api.svg?branch=master 175 | 176 | [badge.Appveyor]: https://img.shields.io/appveyor/ci/Knuth/js-api.svg?style=for-the-badge&label=build&logo=appveyor&logoColor=white 177 | [badge.Cirrus]: https://api.cirrus-ci.com/github/k-nuth/js-api.svg?branch=master 178 | [badge.version]: https://badge.fury.io/gh/k-nuth%2Fkth-js-api.svg 179 | [badge.release]: https://img.shields.io/github/release/k-nuth/js-api.svg 180 | [badge.c]: https://img.shields.io/badge/C-11-blue.svg?style=flat&logo=c 181 | [badge.telegram]: https://img.shields.io/badge/telegram-badge-blue.svg?logo=telegram&style=for-the-badge 182 | [badge.slack]: https://img.shields.io/badge/slack-badge-orange.svg?logo=slack&style=for-the-badge 183 | 184 | 185 | 186 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /src/errors.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 Knuth Project developers. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | const errors = Object.freeze({ 6 | // general codes 7 | /// The operation finished without errors 8 | success: 0, 9 | /// The operation is deprecated 10 | deprecated: 6, 11 | /// Unknown error 12 | unknown: 43, 13 | /// The resource not exist 14 | notFound: 3, 15 | /// File system error 16 | fileSystem: 42, 17 | /// Non-standard transaction 18 | nonStandard: 17, 19 | /// The operation isn't implemented 20 | notImplemented: 4, 21 | /// Service oversubscribed 22 | oversubscribed: 71, 23 | 24 | // network 25 | // Service is stopped 26 | serviceStopped: 1, 27 | /// The operation failed 28 | operationFailed: 2, 29 | /// Resolving hostname failed 30 | resolveFailed: 7, 31 | /// Unable to reach remote host 32 | networkUnreachable: 8, 33 | /// Address already in use 34 | addressInUse: 9, 35 | /// Incoming connection failed 36 | listenFailed: 10, 37 | /// Connection acceptance failed 38 | acceptFailed: 11, 39 | /// Bad data stream 40 | badStream: 12, 41 | /// Connection timed out 42 | channelTimeout: 13, 43 | /// Address blocked by policy 44 | addressBlocked: 44, 45 | /// Channel stopped 46 | channelStopped: 45, 47 | 48 | /// Unresponsive peer may be throttling 49 | 50 | peerThrottling: 73, 51 | 52 | // database 53 | 54 | /// Block duplicate 55 | 56 | storeBlockDuplicate: 66, 57 | 58 | /// Block out of order 59 | 60 | storeBlockInvalidHeight: 67, 61 | 62 | /// Block missing parent 63 | 64 | storeBlockMissingParent: 68, 65 | 66 | // blockchain 67 | 68 | /// Duplicate block 69 | 70 | duplicateBlock: 51, 71 | 72 | /// Missing block parent 73 | 74 | orphanBlock: 5, 75 | 76 | /// Previous block failed to validate 77 | 78 | invalidPreviousBlock: 24, 79 | 80 | /// Insufficient work to reorganize 81 | 82 | insufficientWork: 48, 83 | 84 | /// Transaction parent missing 85 | 86 | orphanTransaction: 14, 87 | 88 | /// Insufficient transaction fee 89 | 90 | insufficientFee: 70, 91 | 92 | /// Output value too low 93 | 94 | dustyTransaction: 76, 95 | 96 | /// Blockchain too far behind 97 | 98 | staleChain: 75, 99 | 100 | // check header 101 | 102 | /// Proof of work invalid 103 | 104 | invalidProofOfWork: 26, 105 | 106 | /// Timestamp too far in the future 107 | 108 | futuristicTimestamp: 27, 109 | 110 | // accept header 111 | 112 | /// Block hash rejected by checkpoint 113 | 114 | checkpointsFailed: 35, 115 | 116 | /// Block version rejected at current height 117 | 118 | oldVersionBlock: 36, 119 | 120 | /// Proof of work does not match bits field 121 | 122 | incorrectProofOfWork: 32, 123 | 124 | /// Block timestamp is too early 125 | 126 | timestampTooEarly: 33, 127 | 128 | // check block 129 | 130 | /// Block size limit exceeded 131 | 132 | blockSizeLimit: 50, 133 | 134 | /// Block has no transactions 135 | 136 | emptyBlock: 47, 137 | 138 | /// First transaction not a coinbase 139 | 140 | firstNotCoinbase: 28, 141 | 142 | /// More than one coinbase 143 | 144 | extraCoinbases: 29, 145 | 146 | /// Matching transaction hashes in block 147 | 148 | internalDuplicate: 49, 149 | 150 | /// Double spend internal to block 151 | 152 | blockInternalDoubleSpend: 15, 153 | 154 | /// Merkle root mismatch 155 | 156 | merkleMismatch: 31, 157 | 158 | /// Too many block legacy signature operations 159 | 160 | blockLegacySigopLimit: 30, 161 | 162 | /// Transactions out of order 163 | 164 | forwardReference: 79, 165 | 166 | // accept block 167 | 168 | /// Block contains a non-final transaction 169 | 170 | blockNonFinal: 34, 171 | 172 | /// Block height mismatch in coinbase 173 | 174 | coinbaseHeightMismatch: 37, 175 | 176 | /// Coinbase value too high 177 | 178 | coinbaseValueLimit: 41, 179 | 180 | /// Too many block embedded signature operations 181 | 182 | blockEmbeddedSigopLimit: 52, 183 | 184 | /// Invalid witness commitment 185 | 186 | invalidWitnessCommitment: 25, 187 | 188 | /// Block weight limit exceeded 189 | 190 | blockWeightLimit: 82, 191 | 192 | // check transaction 193 | 194 | /// Transaction inputs or outputs empty 195 | 196 | emptyTransaction: 20, 197 | 198 | /// Non-coinbase transaction has input with null previous output 199 | 200 | previousOutputNull: 23, 201 | 202 | /// Spend outside valid range 203 | 204 | spendOverflow: 21, 205 | 206 | /// Coinbase script too small or large 207 | 208 | invalidCoinbaseScriptSize: 22, 209 | 210 | /// Coinbase transaction disallowed in memory pool 211 | 212 | coinbaseTransaction: 16, 213 | 214 | /// Double spend internal to transaction 215 | 216 | transactionInternalDoubleSpend: 72, 217 | 218 | /// Transaction size limit exceeded 219 | 220 | transactionSizeLimit: 53, 221 | 222 | /// Too many transaction legacy signature operations 223 | 224 | transactionLegacySigopLimit: 54, 225 | 226 | // accept transaction 227 | 228 | /// Transaction currently non-final for next block 229 | 230 | transactionNonFinal: 74, 231 | 232 | /// Transaction validation under checkpoint 233 | 234 | prematureValidation: 69, 235 | 236 | /// Matching transaction with unspent outputs 237 | 238 | unspentDuplicate: 38, 239 | 240 | /// Previous output not found 241 | 242 | missingPreviousOutput: 19, 243 | 244 | /// double spend of input 245 | 246 | doubleSpend: 18, 247 | 248 | /// Immature coinbase spent 249 | 250 | coinbaseMaturity: 46, 251 | 252 | /// Spend exceeds input values sum 253 | 254 | spendExceedsValue: 40, 255 | 256 | /// Too many transaction embedded signature operations 257 | 258 | transactionEmbeddedSigopLimit: 55, 259 | 260 | /// Transaction currently locked 261 | 262 | sequenceLocked: 78, 263 | 264 | /// Transaction weight limit exceeded 265 | 266 | transactionWeightLimit: 83, 267 | 268 | // connect input 269 | 270 | /// Invalid script 271 | 272 | invalidScript: 39, 273 | 274 | /// Invalid script size 275 | 276 | invalidScriptSize: 56, 277 | 278 | /// Invalid push data size 279 | 280 | invalidPushDataSize: 57, 281 | 282 | /// Invalid operation count 283 | 284 | invalidOperationCount: 58, 285 | 286 | /// Invalid stack size 287 | 288 | invalidStackSize: 59, 289 | 290 | /// Invalid stack scope 291 | 292 | invalidStackScope: 60, 293 | 294 | /// Invalid script embed 295 | 296 | invalidScriptEmbed: 61, 297 | 298 | /// Invalid signature encoding 299 | 300 | invalidSignatureEncoding: 62, 301 | 302 | /// Invalid signature lax encoding 303 | 304 | invalidSignatureLaxEncoding: 63, 305 | 306 | /// Incorrect signature 307 | 308 | incorrectSignature: 64, 309 | 310 | /// Error processing script 311 | 312 | stackFalse: 65, 313 | 314 | /// Unexpected witness 315 | 316 | unexpectedWitness: 77, 317 | 318 | /// Invalid witness 319 | 320 | invalidWitness: 80, 321 | 322 | /// Dirty witness 323 | 324 | dirtyWitness: 81, 325 | 326 | // op eval 327 | opDisabled: 100, 328 | opReserved: 101, 329 | opPushSize: 102, 330 | opPushData: 103, 331 | opIf: 104, 332 | opNotIf: 105, 333 | opElse: 106, 334 | opEndIf: 107, 335 | opVerify1: 108, 336 | opVerify2: 109, 337 | opReturn: 110, 338 | opToAltStack: 111, 339 | opFromAltStack: 112, 340 | opDrop2: 113, 341 | opDup2: 114, 342 | opDup3: 115, 343 | opOver2: 116, 344 | opRot2: 117, 345 | opSwap2: 118, 346 | opIfDup: 119, 347 | opDrop: 120, 348 | opDup: 121, 349 | opNip: 122, 350 | opOver: 123, 351 | opPick: 124, 352 | opRoll: 125, 353 | opRot: 126, 354 | opSwap: 127, 355 | opTuck: 128, 356 | opSize: 129, 357 | opEqual: 130, 358 | opEqualVerify1: 131, 359 | opEqualVerify2: 132, 360 | opAdd1: 133, 361 | opSub1: 134, 362 | opNegate: 135, 363 | opAbs: 136, 364 | opNot: 137, 365 | opNonZero: 138, 366 | opAdd: 139, 367 | opSub: 140, 368 | opBoolAnd: 141, 369 | opBoolOr: 142, 370 | opNumEqual: 143, 371 | opNumEqualVerify1: 144, 372 | opNumEqualVerify2: 145, 373 | opNumNotEqual: 146, 374 | opLessThan: 147, 375 | opGreaterThan: 148, 376 | opLessThanOrEqual: 149, 377 | opGreaterThanOrEqual: 150, 378 | opMin: 151, 379 | opMax: 152, 380 | opWithin: 153, 381 | opRipemd160: 154, 382 | opSha1: 155, 383 | opSha256: 156, 384 | opHash160: 157, 385 | opHash256: 158, 386 | opCodeSeperator: 159, 387 | opCheckSigVerify1: 160, 388 | opCheckSig: 161, 389 | opCheckMultisigVerify1: 162, 390 | opCheckMultisigVerify2: 163, 391 | opCheckMultisigVerify3: 164, 392 | opCheckMultisigVerify4: 165, 393 | opCheckMultisigVerify5: 166, 394 | opCheckMultisigVerify6: 167, 395 | opCheckMultisigVerify7: 168, 396 | opCheckMultisig: 169, 397 | opCheckLocktimeVerify1: 170, 398 | opCheckLocktimeVerify2: 171, 399 | opCheckLocktimeVerify3: 172, 400 | opCheckLocktimeVerify4: 173, 401 | opCheckLocktimeVerify5: 174, 402 | opCheckLocktimeVerify6: 175, 403 | opCheckSequenceVerify1: 176, 404 | opCheckSequenceVerify2: 177, 405 | opCheckSequenceVerify3: 178, 406 | opCheckSequenceVerify4: 179, 407 | opCheckSequenceVerify5: 180, 408 | opCheckSequenceVerify6: 181, 409 | opCheckSequenceVerify7: 182 410 | }); 411 | 412 | exports.errors = errors; 413 | -------------------------------------------------------------------------------- /test/config/settings.test.js: -------------------------------------------------------------------------------- 1 | const settings = require('../../src/config/settings'); 2 | const network = require('../../src/config/network'); 3 | const enc = require('../../src/encoding'); 4 | const primitives = require('../../src/primitives'); 5 | 6 | test('read default mainnet settings', () => { 7 | const setts = settings.getDefault(network.Network.mainnet); 8 | 9 | expect(setts.chain.cores).toBe(0); 10 | expect(setts.chain.priority).toBe(true); 11 | expect(setts.chain.byteFeeSatoshis).toBeCloseTo(0.1); 12 | expect(setts.chain.sigopFeeSatoshis).toBe(100.0); 13 | expect(setts.chain.minimumOutputSatoshis).toBe(500); 14 | expect(setts.chain.notifyLimitHours).toBe(24); 15 | expect(setts.chain.reorganizationLimit).toBe(256); 16 | expect(setts.chain.checkpoints.length).toBe(79); 17 | expect(setts.chain.checkpoints[0].height).toBe(0); 18 | expect(enc.Hash.bytesToStr(setts.chain.checkpoints[0].hash)).toBe( 19 | '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f' 20 | ); 21 | expect(setts.chain.fixCheckpoints).toBe(true); 22 | expect(setts.chain.allowCollisions).toBe(true); 23 | expect(setts.chain.easyBlocks).toBe(false); 24 | expect(setts.chain.retarget).toBe(true); 25 | expect(setts.chain.bip16).toBe(true); 26 | expect(setts.chain.bip30).toBe(true); 27 | expect(setts.chain.bip34).toBe(true); 28 | expect(setts.chain.bip66).toBe(true); 29 | expect(setts.chain.bip65).toBe(true); 30 | expect(setts.chain.bip90).toBe(true); 31 | expect(setts.chain.bip68).toBe(true); 32 | expect(setts.chain.bip112).toBe(true); 33 | expect(setts.chain.bip113).toBe(true); 34 | expect(setts.chain.bchUahf).toBe(true); 35 | expect(setts.chain.bchDaaCw144).toBe(true); 36 | expect(setts.chain.bchPythagoras).toBe(true); 37 | expect(setts.chain.bchEuclid).toBe(true); 38 | expect(setts.chain.bchPisano).toBe(true); 39 | expect(setts.chain.bchMersenne).toBe(true); 40 | expect(setts.chain.bchFermat).toBe(true); 41 | expect(setts.chain.bchEuler).toBe(true); 42 | expect(setts.chain.bchGauss).toBe(true); 43 | expect(setts.chain.bchDescartes).toBe(true); 44 | expect(setts.chain.bchLobachevski).toBe(true); 45 | 46 | expect(setts.chain.galoisActivationTime).toBe(1747310400); 47 | expect(setts.chain.leibnizActivationTime).toBe(1778846400); 48 | 49 | expect(setts.chain.asertHalfLife).toBe(2 * 24 * 60 * 60); //two days 50 | // ------------------------------------------------------------------------------------ 51 | expect(setts.database.directory).toBe('blockchain'); 52 | expect(setts.database.dbMode).toBe(primitives.DbMode.normal); 53 | expect(setts.database.reorgPoolLimit).toBe(100); 54 | expect(setts.database.dbMaxSize).toBe(200 * 1024 * 1024 * 1024); 55 | // expect(setts.database.dbMaxSize).toBe(600 * 1024 * 1024 * 1024); 56 | expect(setts.database.safeMode).toBe(true); 57 | expect(setts.database.cacheCapacity).toBe(0); 58 | // ------------------------------------------------------------------------------------ 59 | expect(setts.network.threads).toBe(0); 60 | expect(setts.network.protocolMaximum).toBe(70015); 61 | expect(setts.network.protocolMinimum).toBe(31402); 62 | expect(setts.network.services).toBe(1); 63 | expect(setts.network.invalidServices).toBe(0); 64 | expect(setts.network.relayTransactions).toBe(true); 65 | expect(setts.network.validateChecksum).toBe(false); 66 | expect(setts.network.identifier).toBe(3908297187); 67 | expect(setts.network.inboundPort).toBe(8333); 68 | expect(setts.network.inboundConnections).toBe(0); 69 | expect(setts.network.outboundConnections).toBe(8); 70 | expect(setts.network.manualAttemptLimit).toBe(0); 71 | expect(setts.network.connectBatchSize).toBe(5); 72 | expect(setts.network.connectTimeoutSeconds).toBe(5); 73 | expect(setts.network.channelHandshakeSeconds).toBe(6000); 74 | expect(setts.network.channelHeartbeatMinutes).toBe(5); 75 | expect(setts.network.channelInactivityMinutes).toBe(10); 76 | expect(setts.network.channelExpirationMinutes).toBe(60); 77 | expect(setts.network.channelGerminationSeconds).toBe(30); 78 | expect(setts.network.hostPoolCapacity).toBe(1000); 79 | expect(setts.network.hostsFile).toBe('hosts.cache'); 80 | // expect(setts.network.self.ip).toBe('0.0.0.0'); 81 | expect(setts.network.self.port).toBe(0); 82 | expect(setts.network.blacklist.length).toBe(0); 83 | expect(setts.network.peers.length).toBe(0); 84 | expect(setts.network.seeds.length).toBe(6); 85 | expect(setts.network.seeds[0].scheme).toBe(''); 86 | expect(setts.network.seeds[0].host).toBe('seed.flowee.cash'); 87 | expect(setts.network.seeds[0].port).toBe(8333); 88 | expect(setts.network.debugFile).toBe('debug.log'); 89 | expect(setts.network.errorFile).toBe('error.log'); 90 | expect(setts.network.archiveDirectory).toBe('archive'); 91 | expect(setts.network.rotationSize).toBe(0); 92 | expect(setts.network.minimumFreeSpace).toBe(0); 93 | expect(setts.network.maximumArchiveSize).toBe(0); 94 | expect(setts.network.maximumArchiveFiles).toBe(0); 95 | 96 | // Expected: "0.0.0.0" 97 | // Received: "[::ffff:0:0]" 98 | // expect(setts.network.statisticsServer.ip).toBe('0.0.0.0'); 99 | 100 | expect(setts.network.statisticsServer.port).toBe(0); 101 | expect(setts.network.verbose).toBe(false); 102 | expect(setts.network.useIpv6).toBe(true); 103 | expect(setts.network.userAgentBlacklist.length).toBe(1); 104 | expect(setts.network.userAgentBlacklist[0]).toBe('/Bitcoin SV:'); 105 | // ------------------------------------------------------------------------------------ 106 | expect(setts.node.syncPeers).toBe(0); 107 | expect(setts.node.syncTimeoutSeconds).toBe(5); 108 | expect(setts.node.blockLatencySeconds).toBe(60); 109 | expect(setts.node.refreshTransactions).toBe(true); 110 | expect(setts.node.compactBlocksHighBandwidth).toBe(true); 111 | }); 112 | 113 | test('read default testnet4 settings', () => { 114 | const setts = settings.getDefault(network.Network.testnet4); 115 | 116 | expect(setts.chain.cores).toBe(0); 117 | expect(setts.chain.priority).toBe(true); 118 | expect(setts.chain.byteFeeSatoshis).toBeCloseTo(0.1); 119 | expect(setts.chain.sigopFeeSatoshis).toBe(100.0); 120 | expect(setts.chain.minimumOutputSatoshis).toBe(500); 121 | expect(setts.chain.notifyLimitHours).toBe(24); 122 | expect(setts.chain.reorganizationLimit).toBe(256); 123 | expect(setts.chain.checkpoints.length).toBe(18); 124 | expect(setts.chain.checkpoints[0].height).toBe(0); 125 | expect(enc.Hash.bytesToStr(setts.chain.checkpoints[0].hash)).toBe( 126 | '000000001dd410c49a788668ce26751718cc797474d3152a5fc073dd44fd9f7b' 127 | ); 128 | expect(setts.chain.fixCheckpoints).toBe(true); 129 | expect(setts.chain.allowCollisions).toBe(true); 130 | expect(setts.chain.easyBlocks).toBe(true); 131 | expect(setts.chain.retarget).toBe(true); 132 | expect(setts.chain.bip16).toBe(true); 133 | expect(setts.chain.bip30).toBe(true); 134 | expect(setts.chain.bip34).toBe(true); 135 | expect(setts.chain.bip66).toBe(true); 136 | expect(setts.chain.bip65).toBe(true); 137 | expect(setts.chain.bip90).toBe(true); 138 | expect(setts.chain.bip68).toBe(true); 139 | expect(setts.chain.bip112).toBe(true); 140 | expect(setts.chain.bip113).toBe(true); 141 | expect(setts.chain.bchUahf).toBe(true); 142 | expect(setts.chain.bchDaaCw144).toBe(true); 143 | expect(setts.chain.bchPythagoras).toBe(true); 144 | expect(setts.chain.bchEuclid).toBe(true); 145 | expect(setts.chain.bchPisano).toBe(true); 146 | expect(setts.chain.bchMersenne).toBe(true); 147 | expect(setts.chain.bchFermat).toBe(true); 148 | expect(setts.chain.bchEuler).toBe(true); 149 | expect(setts.chain.bchGauss).toBe(true); 150 | expect(setts.chain.bchDescartes).toBe(true); 151 | expect(setts.chain.bchLobachevski).toBe(true); 152 | 153 | expect(setts.chain.galoisActivationTime).toBe(1747310400); 154 | expect(setts.chain.leibnizActivationTime).toBe(1778846400); 155 | 156 | expect(setts.chain.asertHalfLife).toBe(60 * 60); // one hour 157 | // ------------------------------------------------------------------------------------ 158 | expect(setts.database.directory).toBe('blockchain'); 159 | expect(setts.database.dbMode).toBe(primitives.DbMode.normal); 160 | expect(setts.database.reorgPoolLimit).toBe(100); 161 | expect(setts.database.dbMaxSize).toBe(20 * 1024 * 1024 * 1024); // 20 GiB 162 | expect(setts.database.safeMode).toBe(true); 163 | expect(setts.database.cacheCapacity).toBe(0); 164 | // ------------------------------------------------------------------------------------ 165 | expect(setts.network.threads).toBe(0); 166 | expect(setts.network.protocolMaximum).toBe(70015); 167 | expect(setts.network.protocolMinimum).toBe(31402); 168 | expect(setts.network.services).toBe(1); 169 | expect(setts.network.invalidServices).toBe(0); 170 | expect(setts.network.relayTransactions).toBe(true); 171 | expect(setts.network.validateChecksum).toBe(false); 172 | expect(setts.network.identifier).toBe(2950346722); 173 | expect(setts.network.inboundPort).toBe(28333); 174 | expect(setts.network.inboundConnections).toBe(0); 175 | expect(setts.network.outboundConnections).toBe(8); 176 | expect(setts.network.manualAttemptLimit).toBe(0); 177 | expect(setts.network.connectBatchSize).toBe(5); 178 | expect(setts.network.connectTimeoutSeconds).toBe(5); 179 | expect(setts.network.channelHandshakeSeconds).toBe(6000); 180 | expect(setts.network.channelHeartbeatMinutes).toBe(5); 181 | expect(setts.network.channelInactivityMinutes).toBe(10); 182 | expect(setts.network.channelExpirationMinutes).toBe(60); 183 | expect(setts.network.channelGerminationSeconds).toBe(30); 184 | expect(setts.network.hostPoolCapacity).toBe(1000); 185 | expect(setts.network.hostsFile).toBe('hosts.cache'); 186 | // expect(setts.network.self.ip).toBe('0.0.0.0'); 187 | expect(setts.network.self.port).toBe(0); 188 | expect(setts.network.blacklist.length).toBe(0); 189 | expect(setts.network.peers.length).toBe(0); 190 | expect(setts.network.seeds.length).toBe(3); 191 | expect(setts.network.seeds[0].scheme).toBe(''); 192 | expect(setts.network.seeds[0].host).toBe('testnet4-seed-bch.bitcoinforks.org'); 193 | expect(setts.network.seeds[0].port).toBe(28333); 194 | expect(setts.network.debugFile).toBe('debug.log'); 195 | expect(setts.network.errorFile).toBe('error.log'); 196 | expect(setts.network.archiveDirectory).toBe('archive'); 197 | expect(setts.network.rotationSize).toBe(0); 198 | expect(setts.network.minimumFreeSpace).toBe(0); 199 | expect(setts.network.maximumArchiveSize).toBe(0); 200 | expect(setts.network.maximumArchiveFiles).toBe(0); 201 | 202 | // Expected: "0.0.0.0" 203 | // Received: "[::ffff:0:0]" 204 | // expect(setts.network.statisticsServer.ip).toBe('0.0.0.0'); 205 | 206 | expect(setts.network.statisticsServer.port).toBe(0); 207 | expect(setts.network.verbose).toBe(false); 208 | expect(setts.network.useIpv6).toBe(true); 209 | expect(setts.network.userAgentBlacklist.length).toBe(1); 210 | expect(setts.network.userAgentBlacklist[0]).toBe('/Bitcoin SV:'); 211 | // ------------------------------------------------------------------------------------ 212 | expect(setts.node.syncPeers).toBe(0); 213 | expect(setts.node.syncTimeoutSeconds).toBe(5); 214 | expect(setts.node.blockLatencySeconds).toBe(60); 215 | expect(setts.node.refreshTransactions).toBe(true); 216 | expect(setts.node.compactBlocksHighBandwidth).toBe(true); 217 | }); 218 | 219 | test('read default chipnet settings', () => { 220 | const setts = settings.getDefault(network.Network.chipnet); 221 | 222 | expect(setts.chain.cores).toBe(0); 223 | expect(setts.chain.priority).toBe(true); 224 | expect(setts.chain.byteFeeSatoshis).toBeCloseTo(0.1); 225 | expect(setts.chain.sigopFeeSatoshis).toBe(100.0); 226 | expect(setts.chain.minimumOutputSatoshis).toBe(500); 227 | expect(setts.chain.notifyLimitHours).toBe(24); 228 | expect(setts.chain.reorganizationLimit).toBe(256); 229 | expect(setts.chain.checkpoints.length).toBe(14); 230 | expect(setts.chain.checkpoints[0].height).toBe(0); 231 | expect(enc.Hash.bytesToStr(setts.chain.checkpoints[0].hash)).toBe( 232 | '000000001dd410c49a788668ce26751718cc797474d3152a5fc073dd44fd9f7b' 233 | ); 234 | expect(setts.chain.fixCheckpoints).toBe(true); 235 | expect(setts.chain.allowCollisions).toBe(true); 236 | expect(setts.chain.easyBlocks).toBe(true); 237 | expect(setts.chain.retarget).toBe(true); 238 | expect(setts.chain.bip16).toBe(true); 239 | expect(setts.chain.bip30).toBe(true); 240 | expect(setts.chain.bip34).toBe(true); 241 | expect(setts.chain.bip66).toBe(true); 242 | expect(setts.chain.bip65).toBe(true); 243 | expect(setts.chain.bip90).toBe(true); 244 | expect(setts.chain.bip68).toBe(true); 245 | expect(setts.chain.bip112).toBe(true); 246 | expect(setts.chain.bip113).toBe(true); 247 | expect(setts.chain.bchUahf).toBe(true); 248 | expect(setts.chain.bchDaaCw144).toBe(true); 249 | expect(setts.chain.bchPythagoras).toBe(true); 250 | expect(setts.chain.bchEuclid).toBe(true); 251 | expect(setts.chain.bchPisano).toBe(true); 252 | expect(setts.chain.bchMersenne).toBe(true); 253 | expect(setts.chain.bchFermat).toBe(true); 254 | expect(setts.chain.bchEuler).toBe(true); 255 | expect(setts.chain.bchGauss).toBe(true); 256 | expect(setts.chain.bchDescartes).toBe(true); 257 | expect(setts.chain.bchLobachevski).toBe(true); 258 | 259 | expect(setts.chain.galoisActivationTime).toBe(1747310400); 260 | expect(setts.chain.leibnizActivationTime).toBe(1778846400); 261 | 262 | expect(setts.chain.asertHalfLife).toBe(60 * 60); // one hour 263 | // ------------------------------------------------------------------------------------ 264 | expect(setts.database.directory).toBe('blockchain'); 265 | expect(setts.database.dbMode).toBe(primitives.DbMode.normal); 266 | expect(setts.database.reorgPoolLimit).toBe(100); 267 | expect(setts.database.dbMaxSize).toBe(20 * 1024 * 1024 * 1024); // 20 GiB 268 | expect(setts.database.safeMode).toBe(true); 269 | expect(setts.database.cacheCapacity).toBe(0); 270 | // ------------------------------------------------------------------------------------ 271 | expect(setts.network.threads).toBe(0); 272 | expect(setts.network.protocolMaximum).toBe(70015); 273 | expect(setts.network.protocolMinimum).toBe(31402); 274 | expect(setts.network.services).toBe(1); 275 | expect(setts.network.invalidServices).toBe(0); 276 | expect(setts.network.relayTransactions).toBe(true); 277 | expect(setts.network.validateChecksum).toBe(false); 278 | expect(setts.network.identifier).toBe(2950346722); 279 | expect(setts.network.inboundPort).toBe(48333); 280 | expect(setts.network.inboundConnections).toBe(0); 281 | expect(setts.network.outboundConnections).toBe(8); 282 | expect(setts.network.manualAttemptLimit).toBe(0); 283 | expect(setts.network.connectBatchSize).toBe(5); 284 | expect(setts.network.connectTimeoutSeconds).toBe(5); 285 | expect(setts.network.channelHandshakeSeconds).toBe(6000); 286 | expect(setts.network.channelHeartbeatMinutes).toBe(5); 287 | expect(setts.network.channelInactivityMinutes).toBe(10); 288 | expect(setts.network.channelExpirationMinutes).toBe(60); 289 | expect(setts.network.channelGerminationSeconds).toBe(30); 290 | expect(setts.network.hostPoolCapacity).toBe(1000); 291 | expect(setts.network.hostsFile).toBe('hosts.cache'); 292 | // expect(setts.network.self.ip).toBe('0.0.0.0'); 293 | expect(setts.network.self.port).toBe(0); 294 | expect(setts.network.blacklist.length).toBe(0); 295 | expect(setts.network.peers.length).toBe(0); 296 | expect(setts.network.seeds.length).toBe(1); 297 | expect(setts.network.seeds[0].scheme).toBe(''); 298 | expect(setts.network.seeds[0].host).toBe('chipnet.bitjson.com'); 299 | expect(setts.network.seeds[0].port).toBe(48333); 300 | expect(setts.network.debugFile).toBe('debug.log'); 301 | expect(setts.network.errorFile).toBe('error.log'); 302 | expect(setts.network.archiveDirectory).toBe('archive'); 303 | expect(setts.network.rotationSize).toBe(0); 304 | expect(setts.network.minimumFreeSpace).toBe(0); 305 | expect(setts.network.maximumArchiveSize).toBe(0); 306 | expect(setts.network.maximumArchiveFiles).toBe(0); 307 | 308 | // Expected: "0.0.0.0" 309 | // Received: "[::ffff:0:0]" 310 | // expect(setts.network.statisticsServer.ip).toBe('0.0.0.0'); 311 | 312 | expect(setts.network.statisticsServer.port).toBe(0); 313 | expect(setts.network.verbose).toBe(false); 314 | expect(setts.network.useIpv6).toBe(true); 315 | expect(setts.network.userAgentBlacklist.length).toBe(1); 316 | expect(setts.network.userAgentBlacklist[0]).toBe('/Bitcoin SV:'); 317 | // ------------------------------------------------------------------------------------ 318 | expect(setts.node.syncPeers).toBe(0); 319 | expect(setts.node.syncTimeoutSeconds).toBe(5); 320 | expect(setts.node.blockLatencySeconds).toBe(60); 321 | expect(setts.node.refreshTransactions).toBe(true); 322 | expect(setts.node.compactBlocksHighBandwidth).toBe(true); 323 | }); 324 | -------------------------------------------------------------------------------- /examples/subscription/kth-inside.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 25 | 28 | 32 | 33 | 36 | 41 | 42 | 45 | 49 | 50 | 53 | 57 | 58 | 61 | 66 | 67 | 70 | 74 | 75 | 78 | 82 | 83 | 86 | 90 | 91 | 100 | 104 | 108 | 109 | 118 | 122 | 126 | 127 | 130 | 134 | 135 | 138 | 142 | 143 | 152 | 156 | 160 | 161 | 170 | 174 | 178 | 179 | 182 | 186 | 187 | 190 | 194 | 195 | 198 | 202 | 203 | 206 | 210 | 211 | 214 | 218 | 219 | 222 | 226 | 227 | 234 | 241 | 242 | 245 | 249 | 250 | 257 | 264 | 265 | 272 | 279 | 280 | 287 | 288 | 315 | 317 | 318 | 320 | image/svg+xml 321 | 323 | 324 | 325 | 326 | 327 | 332 | 336 | 342 | 348 | 354 | 360 | 366 | 372 | 378 | 384 | 390 | 391 | 397 | 401 | 405 | 409 | 413 | 414 | 420 | 421 | 422 | --------------------------------------------------------------------------------