2019-09-07 13:42:03 +09:00
import * as assert from 'assert' ;
import * as base58 from 'bs58' ;
import { describe , it } from 'mocha' ;
import * as bitcoin from '..' ;
import * as base58EncodeDecode from './fixtures/core/base58_encode_decode.json' ;
import * as base58KeysInvalid from './fixtures/core/base58_keys_invalid.json' ;
import * as base58KeysValid from './fixtures/core/base58_keys_valid.json' ;
import * as blocksValid from './fixtures/core/blocks.json' ;
import * as sigCanonical from './fixtures/core/sig_canonical.json' ;
import * as sigHash from './fixtures/core/sighash.json' ;
import * as sigNoncanonical from './fixtures/core/sig_noncanonical.json' ;
import * as txValid from './fixtures/core/tx_valid.json' ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
describe ( 'Bitcoin-core' , ( ) = > {
2016-09-14 22:29:12 +10:00
// base58EncodeDecode
2019-04-09 15:09:50 +09:00
describe ( 'base58' , ( ) = > {
base58EncodeDecode . forEach ( f = > {
2019-09-07 13:42:03 +09:00
const fhex = f [ 0 ] ;
const fb58 = f [ 1 ] ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
it ( 'can decode ' + fb58 , ( ) = > {
2019-09-07 13:42:03 +09:00
const buffer = base58 . decode ( fb58 ) ;
const actual = buffer . toString ( 'hex' ) ;
2014-05-29 01:21:56 +10:00
2019-09-07 13:42:03 +09:00
assert . strictEqual ( actual , fhex ) ;
} ) ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
it ( 'can encode ' + fhex , ( ) = > {
2019-09-07 13:42:03 +09:00
const buffer = Buffer . from ( fhex , 'hex' ) ;
const actual = base58 . encode ( buffer ) ;
2014-05-29 01:21:56 +10:00
2019-09-07 13:42:03 +09:00
assert . strictEqual ( actual , fb58 ) ;
} ) ;
} ) ;
} ) ;
2014-05-29 01:21:56 +10:00
2016-09-14 22:29:12 +10:00
// base58KeysValid
2019-04-09 15:09:50 +09:00
describe ( 'address.toBase58Check' , ( ) = > {
2019-09-07 13:42:03 +09:00
const typeMap : any = {
pubkey : 'pubKeyHash' ,
script : 'scriptHash' ,
} ;
2015-02-23 10:36:57 +11:00
2019-04-09 15:09:50 +09:00
base58KeysValid . forEach ( f = > {
2019-09-07 13:42:03 +09:00
const expected = f [ 0 ] ;
const hash = Buffer . from ( f [ 1 ] as any , 'hex' ) ;
const params = f [ 2 ] as any ;
2014-05-29 01:21:56 +10:00
2019-09-07 13:42:03 +09:00
if ( params . isPrivkey ) return ;
2014-05-29 01:21:56 +10:00
2019-09-07 13:42:03 +09:00
const network : any = params . isTestnet
? bitcoin . networks . testnet
: bitcoin . networks . bitcoin ;
const version = network [ typeMap [ params . addrType ] ] ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
it ( 'can export ' + expected , ( ) = > {
2019-09-07 13:42:03 +09:00
assert . strictEqual (
bitcoin . address . toBase58Check ( hash , version ) ,
expected ,
) ;
} ) ;
} ) ;
} ) ;
2014-05-29 01:21:56 +10:00
2016-09-14 22:29:12 +10:00
// base58KeysInvalid
2019-04-09 15:09:50 +09:00
describe ( 'address.fromBase58Check' , ( ) = > {
2018-06-25 16:37:45 +10:00
const allowedNetworks = [
2019-09-07 13:42:03 +09:00
bitcoin . networks . bitcoin . pubKeyHash ,
bitcoin . networks . bitcoin . scriptHash ,
bitcoin . networks . testnet . pubKeyHash ,
bitcoin . networks . testnet . scriptHash ,
] ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
base58KeysInvalid . forEach ( f = > {
2019-09-07 13:42:03 +09:00
const string = f [ 0 ] ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
it ( 'throws on ' + string , ( ) = > {
assert . throws ( ( ) = > {
2019-09-07 13:42:03 +09:00
const address = bitcoin . address . fromBase58Check ( string ) ;
assert . notStrictEqual (
allowedNetworks . indexOf ( address . version ) ,
- 1 ,
'Invalid network' ,
) ;
} , /(Invalid (checksum|network))|(too (short|long))/ ) ;
} ) ;
} ) ;
} ) ;
2014-05-29 01:21:56 +10:00
2016-09-14 22:29:12 +10:00
// base58KeysValid
2019-04-09 15:09:50 +09:00
describe ( 'ECPair' , ( ) = > {
base58KeysValid . forEach ( f = > {
2019-09-07 13:42:03 +09:00
const strng = f [ 0 ] as string ;
const hex = f [ 1 ] ;
const params = f [ 2 ] as any ;
2014-05-29 01:21:56 +10:00
2019-09-07 13:42:03 +09:00
if ( ! params . isPrivkey ) return ;
2015-07-28 16:42:57 +10:00
2019-09-07 13:42:03 +09:00
const network = params . isTestnet
? bitcoin . networks . testnet
: bitcoin . networks . bitcoin ;
const keyPair = bitcoin . ECPair . fromWIF ( strng , network ) ;
2014-05-29 01:21:56 +10:00
2019-09-07 13:42:03 +09:00
it ( 'fromWIF imports ' + strng , ( ) = > {
assert . strictEqual ( keyPair . privateKey ! . toString ( 'hex' ) , hex ) ;
assert . strictEqual ( keyPair . compressed , params . isCompressed ) ;
} ) ;
2015-02-23 10:26:01 +11:00
2019-09-07 13:42:03 +09:00
it ( 'toWIF exports ' + hex + ' to ' + strng , ( ) = > {
assert . strictEqual ( keyPair . toWIF ( ) , strng ) ;
} ) ;
} ) ;
} ) ;
2014-05-29 01:21:56 +10:00
2016-09-14 22:29:12 +10:00
// base58KeysInvalid
2019-04-09 15:09:50 +09:00
describe ( 'ECPair.fromWIF' , ( ) = > {
2018-06-25 16:37:45 +10:00
const allowedNetworks = [
2015-08-20 13:10:03 +10:00
bitcoin . networks . bitcoin ,
2019-09-07 13:42:03 +09:00
bitcoin . networks . testnet ,
] ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
base58KeysInvalid . forEach ( f = > {
2019-09-07 13:42:03 +09:00
const string = f [ 0 ] ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
it ( 'throws on ' + string , ( ) = > {
assert . throws ( ( ) = > {
2019-09-07 13:42:03 +09:00
bitcoin . ECPair . fromWIF ( string , allowedNetworks ) ;
} , /(Invalid|Unknown) (checksum|compression flag|network version|WIF length)/ ) ;
} ) ;
} ) ;
} ) ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
describe ( 'Block.fromHex' , ( ) = > {
blocksValid . forEach ( f = > {
it ( 'can parse ' + f . id , ( ) = > {
2019-09-07 13:42:03 +09:00
const block = bitcoin . Block . fromHex ( f . hex ) ;
2015-03-05 01:14:48 +11:00
2019-09-07 13:42:03 +09:00
assert . strictEqual ( block . getId ( ) , f . id ) ;
assert . strictEqual ( block . transactions ! . length , f . transactions ) ;
} ) ;
} ) ;
} ) ;
2015-03-05 01:14:48 +11:00
2016-09-14 22:29:12 +10:00
// txValid
2019-04-09 15:09:50 +09:00
describe ( 'Transaction.fromHex' , ( ) = > {
txValid . forEach ( f = > {
2014-05-29 01:21:56 +10:00
// Objects that are only a single string are ignored
2019-09-07 13:42:03 +09:00
if ( f . length === 1 ) return ;
2014-05-29 01:21:56 +10:00
2019-09-07 13:42:03 +09:00
const inputs = f [ 0 ] ;
const fhex = f [ 1 ] ;
2018-06-25 16:37:45 +10:00
// const verifyFlags = f[2] // TODO: do we need to test this?
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
it ( 'can decode ' + fhex , ( ) = > {
2019-09-07 13:42:03 +09:00
const transaction = bitcoin . Transaction . fromHex ( fhex as string ) ;
2014-05-29 01:21:56 +10:00
2019-04-09 15:09:50 +09:00
transaction . ins . forEach ( ( txIn , i ) = > {
2019-09-07 13:42:03 +09:00
const input = inputs [ i ] ;
2015-04-28 10:58:00 +10:00
2015-09-14 15:03:35 +10:00
// reverse because test data is reversed
2019-09-07 13:42:03 +09:00
const prevOutHash = Buffer . from ( input [ 0 ] as string , 'hex' ) . reverse ( ) ;
const prevOutIndex = input [ 1 ] ;
2014-05-29 01:21:56 +10:00
2019-09-07 13:42:03 +09:00
assert . deepStrictEqual ( txIn . hash , prevOutHash ) ;
2014-05-29 01:21:56 +10:00
// we read UInt32, not Int32
2019-09-07 13:42:03 +09:00
assert . strictEqual ( txIn . index & 0xffffffff , prevOutIndex ) ;
} ) ;
} ) ;
} ) ;
} ) ;
2014-05-29 01:21:56 +10:00
// sighash
2019-04-09 15:09:50 +09:00
describe ( 'Transaction' , ( ) = > {
sigHash . forEach ( f = > {
2014-05-29 01:21:56 +10:00
// Objects that are only a single string are ignored
2019-09-07 13:42:03 +09:00
if ( f . length === 1 ) return ;
const txHex = f [ 0 ] as string ;
const scriptHex = f [ 1 ] as string ;
const inIndex = f [ 2 ] as number ;
const hashType = f [ 3 ] as number ;
const expectedHash = f [ 4 ] ;
const hashTypes = [ ] ;
if ( ( hashType & 0x1f ) === bitcoin . Transaction . SIGHASH_NONE )
hashTypes . push ( 'SIGHASH_NONE' ) ;
else if ( ( hashType & 0x1f ) === bitcoin . Transaction . SIGHASH_SINGLE )
hashTypes . push ( 'SIGHASH_SINGLE' ) ;
else hashTypes . push ( 'SIGHASH_ALL' ) ;
if ( hashType & bitcoin . Transaction . SIGHASH_ANYONECANPAY )
hashTypes . push ( 'SIGHASH_ANYONECANPAY' ) ;
const hashTypeName = hashTypes . join ( ' | ' ) ;
it (
'should hash ' + txHex . slice ( 0 , 40 ) + '... (' + hashTypeName + ')' ,
( ) = > {
const transaction = bitcoin . Transaction . fromHex ( txHex ) ;
assert . strictEqual ( transaction . toHex ( ) , txHex ) ;
const script = Buffer . from ( scriptHex , 'hex' ) ;
const scriptChunks = bitcoin . script . decompile ( script ) ;
assert . strictEqual (
bitcoin . script . compile ( scriptChunks ! ) . toString ( 'hex' ) ,
scriptHex ,
) ;
const hash = transaction . hashForSignature ( inIndex , script , hashType ) ;
2015-04-28 10:38:10 +10:00
2019-09-07 13:42:03 +09:00
// reverse because test data is reversed
assert . strictEqual (
( hash . reverse ( ) as Buffer ) . toString ( 'hex' ) ,
expectedHash ,
) ;
} ,
) ;
} ) ;
} ) ;
2014-06-20 15:25:23 +10:00
2019-04-09 15:09:50 +09:00
describe ( 'script.signature.decode' , ( ) = > {
sigCanonical . forEach ( hex = > {
2019-09-07 13:42:03 +09:00
const buffer = Buffer . from ( hex , 'hex' ) ;
2014-06-20 15:25:23 +10:00
2019-04-09 15:09:50 +09:00
it ( 'can parse ' + hex , ( ) = > {
2019-09-07 13:42:03 +09:00
const parsed = bitcoin . script . signature . decode ( buffer ) ;
const actual = bitcoin . script . signature . encode (
parsed . signature ,
parsed . hashType ,
) ;
2016-10-13 23:45:08 +11:00
2019-09-07 13:42:03 +09:00
assert . strictEqual ( actual . toString ( 'hex' ) , hex ) ;
} ) ;
} ) ;
2014-06-20 15:25:23 +10:00
2019-04-09 15:09:50 +09:00
sigNoncanonical . forEach ( ( hex , i ) = > {
2019-09-07 13:42:03 +09:00
if ( i === 0 ) return ;
if ( i % 2 !== 0 ) return ;
2014-06-20 15:25:23 +10:00
2019-09-07 13:42:03 +09:00
const description = sigNoncanonical [ i - 1 ] . slice ( 0 , - 1 ) ;
const buffer = Buffer . from ( hex , 'hex' ) ;
2014-06-20 15:25:23 +10:00
2019-04-09 15:09:50 +09:00
it ( 'throws on ' + description , ( ) = > {
assert . throws ( ( ) = > {
2019-09-07 13:42:03 +09:00
bitcoin . script . signature . decode ( buffer ) ;
} , /Expected DER (integer|sequence)|(R|S) value (excessively padded|is negative)|(R|S|DER sequence) length is (zero|too short|too long|invalid)|Invalid hashType/ ) ;
} ) ;
} ) ;
} ) ;
} ) ;