From 55713070f86279c8ed907ee7ff0b5cbc6a9b77e3 Mon Sep 17 00:00:00 2001 From: Mohamed Barry Date: Wed, 15 Apr 2020 19:33:20 +0100 Subject: [PATCH 1/3] bech32: update files --- BRAddress.c | 86 ++++++++++----- BRAddress.h | 12 ++- BRBIP38Key.c | 6 +- BRBase58.c | 9 +- BRInt.h | 6 +- BRMerkleBlock.c | 21 ++-- BRMerkleBlock.h | 3 + BRPeer.c | 44 ++++---- BRPeer.h | 10 +- BRPeerManager.c | 187 +++++++++++++------------------- BRPeerManager.h | 9 +- BRTransaction.c | 30 +++++- BRTransaction.h | 9 +- BRWallet.c | 3 +- module.modulemap | 2 + test.c | 275 ++++++++++++++++++++++++++++++++++++----------- 16 files changed, 452 insertions(+), 260 deletions(-) diff --git a/BRAddress.c b/BRAddress.c index 1636066f6..800dba15e 100644 --- a/BRAddress.c +++ b/BRAddress.c @@ -24,6 +24,7 @@ #include "BRAddress.h" #include "BRBase58.h" +#include "BRBech32.h" #include "BRInt.h" #include #include @@ -241,20 +242,19 @@ size_t BRAddressFromScriptPubKey(char *addr, size_t addrLen, const uint8_t *scri if (! script || scriptLen == 0 || scriptLen > MAX_SCRIPT_LENGTH) return 0; uint8_t data[21]; - const uint8_t *elems[BRScriptElements(NULL, 0, script, scriptLen)], *d = NULL; - size_t count = BRScriptElements(elems, sizeof(elems)/sizeof(*elems), script, scriptLen), l = 0; - - data[0] = BITCOIN_PUBKEY_ADDRESS; -#if LITECOIN_TESTNET - data[0] = BITCOIN_PUBKEY_ADDRESS_TEST; -#endif - + const uint8_t *d, *elems[BRScriptElements(NULL, 0, script, scriptLen)]; + char a[91]; + size_t r = 0, l = 0, count = BRScriptElements(elems, sizeof(elems)/sizeof(*elems), script, scriptLen); + if (count == 5 && *elems[0] == OP_DUP && *elems[1] == OP_HASH160 && *elems[2] == 20 && *elems[3] == OP_EQUALVERIFY && *elems[4] == OP_CHECKSIG) { // pay-to-pubkey-hash scriptPubKey - d = BRScriptData(elems[2], &l); - if (l != 20) d = NULL; - if (d) memcpy(&data[1], d, 20); + data[0] = BITCOIN_PUBKEY_ADDRESS; +#if LITECOIN_TESTNET + data[0] = BITCOIN_PUBKEY_ADDRESS_TEST; +#endif + memcpy(&data[1], BRScriptData(elems[2], &l), 20); + r = BRBase58CheckEncode(addr, addrLen, data, 21); } else if (count == 3 && *elems[0] == OP_HASH160 && *elems[1] == 20 && *elems[2] == OP_EQUAL) { // pay-to-script-hash scriptPubKey @@ -262,18 +262,31 @@ size_t BRAddressFromScriptPubKey(char *addr, size_t addrLen, const uint8_t *scri #if LITECOIN_TESTNET data[0] = BITCOIN_SCRIPT_ADDRESS_TEST; #endif - d = BRScriptData(elems[1], &l); - if (l != 20) d = NULL; - if (d) memcpy(&data[1], d, 20); + memcpy(&data[1], BRScriptData(elems[1], &l), 20); + r = BRBase58CheckEncode(addr, addrLen, data, 21); } else if (count == 2 && (*elems[0] == 65 || *elems[0] == 33) && *elems[1] == OP_CHECKSIG) { // pay-to-pubkey scriptPubKey + data[0] = BITCOIN_PUBKEY_ADDRESS; +#if LITECOIN_TESTNET + data[0] = BITCOIN_PUBKEY_ADDRESS_TEST; +#endif d = BRScriptData(elems[0], &l); - if (l != 65 && l != 33) d = NULL; - if (d) BRHash160(&data[1], d, l); + BRHash160(&data[1], d, l); + r = BRBase58CheckEncode(addr, addrLen, data, 21); + } + else if (count == 2 && ((*elems[0] == OP_0 && (*elems[1] == 20 || *elems[1] == 32)) || + (*elems[0] >= OP_1 && *elems[0] <= OP_16 && *elems[1] >= 2 && *elems[1] <= 40))) { + // pay-to-witness scriptPubKey + r = BRBech32Encode(a, "ltc", script); +#if LITECOIN_TESTNET + r = BRBech32Encode(a, "tltc", script); +#endif + if (addr && r > addrLen) r = 0; + if (addr) memcpy(addr, a, r); } - return (d) ? BRBase58CheckEncode(addr, addrLen, data, sizeof(data)) : 0; + return r; } // writes the bitcoin address for a scriptSig to addr @@ -310,23 +323,32 @@ size_t BRAddressFromScriptSig(char *addr, size_t addrLen, const uint8_t *script, else if (count >= 1 && *elems[count - 1] <= OP_PUSHDATA4 && *elems[count - 1] > 0) { // pay-to-pubkey scriptSig // TODO: implement Peter Wullie's pubKey recovery from signature } - - return (d) ? BRBase58CheckEncode(addr, addrLen, data, sizeof(data)) : 0; + // pay-to-witness scriptSig's are empty + + return (d) ? BRBase58CheckEncode(addr, addrLen, data, 21) : 0; +} + +// writes the bitcoin address for a witness to addr +// returns the number of bytes written, or addrLen needed if addr is NULL +size_t BRAddressFromWitness(char *addr, size_t addrLen, const uint8_t *witness, size_t witLen) +{ + return 0; // TODO: XXX implement } // writes the scriptPubKey for addr to script // returns the number of bytes written, or scriptLen needed if script is NULL size_t BRAddressScriptPubKey(uint8_t *script, size_t scriptLen, const char *addr) { - static uint8_t pubkeyAddress = BITCOIN_PUBKEY_ADDRESS, scriptAddress = BITCOIN_SCRIPT_ADDRESS; - uint8_t data[21]; - size_t r = 0; + uint8_t data[42], pubkeyAddress = BITCOIN_PUBKEY_ADDRESS, scriptAddress = BITCOIN_SCRIPT_ADDRESS; + char hrp[84], *bech32Prefix = "ltc"; + size_t dataLen, r = 0; assert(addr != NULL); #if LITECOIN_TESTNET pubkeyAddress = BITCOIN_PUBKEY_ADDRESS_TEST; scriptAddress = BITCOIN_SCRIPT_ADDRESS_TEST; + bech32Prefix = "tltc"; #endif if (BRBase58CheckDecode(data, sizeof(data), addr) == 21) { @@ -353,6 +375,14 @@ size_t BRAddressScriptPubKey(uint8_t *script, size_t scriptLen, const char *addr r = (! script || 23 <= scriptLen) ? 23 : 0; } } + else { + dataLen = BRBech32Decode(hrp, data, addr); + + if (dataLen > 2 && strcmp(hrp, bech32Prefix) == 0 && (data[0] != OP_0 || data[1] == 20 || data[1] == 32)) { + if (script && dataLen <= scriptLen) memcpy(script, data, dataLen); + r = (! script || dataLen <= scriptLen) ? dataLen : 0; + } + } return r; } @@ -360,7 +390,8 @@ size_t BRAddressScriptPubKey(uint8_t *script, size_t scriptLen, const char *addr // returns true if addr is a valid bitcoin address int BRAddressIsValid(const char *addr) { - uint8_t data[21]; + uint8_t data[42]; + char hrp[84]; int r = 0; assert(addr != NULL); @@ -372,7 +403,14 @@ int BRAddressIsValid(const char *addr) r = (data[0] == BITCOIN_PUBKEY_ADDRESS_TEST || data[0] == BITCOIN_SCRIPT_ADDRESS_TEST); #endif } - + else if (BRBech32Decode(hrp, data, addr) > 2) { + r = (strcmp(hrp, "ltc") == 0 && (data[0] != OP_0 || data[1] == 20 || data[1] == 32)); + +#if LITECOIN_TESTNET + r = (strcmp(hrp, "tltc") == 0 && (data[0] != OP_0 || data[1] == 20 || data[1] == 32)); +#endif + } + return r; } diff --git a/BRAddress.h b/BRAddress.h index 7a70bde22..14b1aa5b9 100644 --- a/BRAddress.h +++ b/BRAddress.h @@ -49,6 +49,9 @@ extern "C" { #define OP_PUSHDATA1 0x4c #define OP_PUSHDATA2 0x4d #define OP_PUSHDATA4 0x4e +#define OP_1NEGATE 0x4f +#define OP_1 0x51 +#define OP_16 0x60 #define OP_DUP 0x76 #define OP_EQUAL 0x87 #define OP_EQUALVERIFY 0x88 @@ -77,10 +80,11 @@ const uint8_t *BRScriptData(const uint8_t *elem, size_t *dataLen); size_t BRScriptPushData(uint8_t *script, size_t scriptLen, const uint8_t *data, size_t dataLen); typedef struct { - char s[36]; + char s[75]; } BRAddress; -#define BR_ADDRESS_NONE ((BRAddress) { "\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\0\0\0" }) +#define BR_ADDRESS_NONE ((BRAddress) { "\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\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\0\0\0\0\0\0\0\0\0\0" }) // writes the bitcoin address for a scriptPubKey to addr // returns the number of bytes written, or addrLen needed if addr is NULL @@ -90,6 +94,10 @@ size_t BRAddressFromScriptPubKey(char *addr, size_t addrLen, const uint8_t *scri // returns the number of bytes written, or addrLen needed if addr is NULL size_t BRAddressFromScriptSig(char *addr, size_t addrLen, const uint8_t *script, size_t scriptLen); +// writes the bitcoin address for a witness to addr +// returns the number of bytes written, or addrLen needed if addr is NULL +size_t BRAddressFromWitness(char *addr, size_t addrLen, const uint8_t *witness, size_t witLen); + // writes the scriptPubKey for addr to script // returns the number of bytes written, or scriptLen needed if script is NULL size_t BRAddressScriptPubKey(uint8_t *script, size_t scriptLen, const char *addr); diff --git a/BRBIP38Key.c b/BRBIP38Key.c index 6d0cc768f..7068628dd 100644 --- a/BRBIP38Key.c +++ b/BRBIP38Key.c @@ -256,7 +256,7 @@ int BRKeySetBIP38Key(BRKey *key, const char *bip38Key, const char *passphrase) BRScrypt(&derived, sizeof(derived), passphrase, pwLen, addresshash, sizeof(uint32_t), BIP38_SCRYPT_N, BIP38_SCRYPT_R, BIP38_SCRYPT_P); - derived1 = *(UInt256 *)&derived, derived2 = *(UInt256 *)&derived.u64[4]; + derived1 = *(UInt256 *)&derived, derived2 = *(UInt256 *)&derived.u8[sizeof(UInt256)]; var_clean(&derived); _BRAES256ECBDecrypt(&derived2, &encrypted1); @@ -280,7 +280,7 @@ int BRKeySetBIP38Key(BRKey *key, const char *bip38Key, const char *passphrase) BRSecp256k1PointGen(&passpoint, &passfactor); // passpoint = G*passfactor derived = _BRBIP38DeriveKey(passpoint, addresshash, entropy); var_clean(&passpoint); - derived1 = *(UInt256 *)&derived, derived2 = *(UInt256 *)&derived.u64[4]; + derived1 = *(UInt256 *)&derived, derived2 = *(UInt256 *)&derived.u8[sizeof(UInt256)]; var_clean(&derived); memcpy(&encrypted1, &data[15], sizeof(uint64_t)); @@ -365,7 +365,7 @@ size_t BRKeyBIP38Key(BRKey *key, char *bip38Key, size_t bip38KeyLen, const char BRScrypt(&derived, sizeof(derived), passphrase, strlen(passphrase), &salt, sizeof(salt), BIP38_SCRYPT_N, BIP38_SCRYPT_R, BIP38_SCRYPT_P); - derived1 = *(UInt256 *)&derived, derived2 = *(UInt256 *)&derived.u64[4]; + derived1 = *(UInt256 *)&derived, derived2 = *(UInt256 *)&derived.u8[sizeof(UInt256)]; var_clean(&derived); // enctryped1 = AES256Encrypt(privkey[0...15] xor derived1[0...15], derived2) diff --git a/BRBase58.c b/BRBase58.c index da0e54396..df23a6fc5 100644 --- a/BRBase58.c +++ b/BRBase58.c @@ -32,11 +32,10 @@ // base58 and base58check encoding: https://en.bitcoin.it/wiki/Base58Check_encoding -static const char base58chars[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - // returns the number of characters written to str including NULL terminator, or total strLen needed if str is NULL size_t BRBase58Encode(char *str, size_t strLen, const uint8_t *data, size_t dataLen) { + static const char chars[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; size_t i, j, len, zcount = 0; assert(data != NULL); @@ -63,8 +62,8 @@ size_t BRBase58Encode(char *str, size_t strLen, const uint8_t *data, size_t data len = (zcount + sizeof(buf) - i) + 1; if (str && len <= strLen) { - while (zcount-- > 0) *(str++) = base58chars[0]; - while (i < sizeof(buf)) *(str++) = base58chars[buf[i++]]; + while (zcount-- > 0) *(str++) = chars[0]; + while (i < sizeof(buf)) *(str++) = chars[buf[i++]]; *str = '\0'; } @@ -78,7 +77,7 @@ size_t BRBase58Decode(uint8_t *data, size_t dataLen, const char *str) size_t i = 0, j, len, zcount = 0; assert(str != NULL); - while (str && *str == base58chars[0]) str++, zcount++; // count leading zeroes + while (str && *str == '1') str++, zcount++; // count leading zeroes uint8_t buf[(str) ? strlen(str)*733/1000 + 1 : 0]; // log(58)/log(256), rounded up diff --git a/BRInt.h b/BRInt.h index bd8818d6c..607743c8e 100644 --- a/BRInt.h +++ b/BRInt.h @@ -117,7 +117,7 @@ inline static UInt256 UInt256Reverse(UInt256 u) // hex encoding/decoding -#define u256_hex_encode(u) ((const char[]) {\ +#define u256hex(u) ((const char[]) {\ _hexc((u).u8[ 0] >> 4), _hexc((u).u8[ 0]), _hexc((u).u8[ 1] >> 4), _hexc((u).u8[ 1]),\ _hexc((u).u8[ 2] >> 4), _hexc((u).u8[ 2]), _hexc((u).u8[ 3] >> 4), _hexc((u).u8[ 3]),\ _hexc((u).u8[ 4] >> 4), _hexc((u).u8[ 4]), _hexc((u).u8[ 5] >> 4), _hexc((u).u8[ 5]),\ @@ -135,7 +135,7 @@ inline static UInt256 UInt256Reverse(UInt256 u) _hexc((u).u8[28] >> 4), _hexc((u).u8[28]), _hexc((u).u8[29] >> 4), _hexc((u).u8[29]),\ _hexc((u).u8[30] >> 4), _hexc((u).u8[30]), _hexc((u).u8[31] >> 4), _hexc((u).u8[31]), '\0' }) -#define u256_hex_decode(s) ((UInt256) { .u8 = {\ +#define uint256(s) ((UInt256) { .u8 = {\ (_hexu((s)[ 0]) << 4) | _hexu((s)[ 1]), (_hexu((s)[ 2]) << 4) | _hexu((s)[ 3]),\ (_hexu((s)[ 4]) << 4) | _hexu((s)[ 5]), (_hexu((s)[ 6]) << 4) | _hexu((s)[ 7]),\ (_hexu((s)[ 8]) << 4) | _hexu((s)[ 9]), (_hexu((s)[10]) << 4) | _hexu((s)[11]),\ @@ -155,7 +155,7 @@ inline static UInt256 UInt256Reverse(UInt256 u) #define _hexc(u) (((u) & 0x0f) + ((((u) & 0x0f) <= 9) ? '0' : 'a' - 0x0a)) #define _hexu(c) (((c) >= '0' && (c) <= '9') ? (c) - '0' : ((c) >= 'a' && (c) <= 'f') ? (c) - ('a' - 0x0a) :\ - ((c) >= 'A' && (c) <= 'F') ? (c) - ('A' - 0x0a) : 0) + ((c) >= 'A' && (c) <= 'F') ? (c) - ('A' - 0x0a) : -1) // unaligned memory access helpers diff --git a/BRMerkleBlock.c b/BRMerkleBlock.c index d30aa81f3..c74b42012 100644 --- a/BRMerkleBlock.c +++ b/BRMerkleBlock.c @@ -32,7 +32,7 @@ #include #define MAX_PROOF_OF_WORK 0x1e0fffff // highest value for difficulty target (higher values are less difficult) -#define TARGET_TIMESPAN 302400 // the targeted timespan between difficulty target adjustments (3.5*24*60*60) +#define TARGET_TIMESPAN 302400 // = 3.5*24*60*60; the targeted timespan between difficulty target adjustments inline static int _ceil_log2(int x) { @@ -83,6 +83,19 @@ BRMerkleBlock *BRMerkleBlockNew(void) return block; } +// returns a deep copy of block and that must be freed by calling BRMerkleBlockFree() +BRMerkleBlock *BRMerkleBlockCopy(const BRMerkleBlock *block) +{ + BRMerkleBlock *cpy = BRMerkleBlockNew(); + + assert(block != NULL); + *cpy = *block; + cpy->hashes = NULL; + cpy->flags = NULL; + BRMerkleBlockSetTxHashes(cpy, block->hashes, block->hashesCount, block->flags, block->flagsLen); + return cpy; +} + // buf must contain either a serialized merkleblock or header // returns a merkle block struct that must be freed by calling BRMerkleBlockFree() BRMerkleBlock *BRMerkleBlockParse(const uint8_t *buf, size_t bufLen) @@ -321,13 +334,7 @@ int BRMerkleBlockVerifyDifficulty(const BRMerkleBlock *block, const BRMerkleBloc if (! previous || !UInt256Eq(block->prevBlock, previous->blockHash) || block->height != previous->height + 1) r = 0; if (r && (block->height % BLOCK_DIFFICULTY_INTERVAL) == 0 && transitionTime == 0) r = 0; - -#if LITECOIN_TESTNET - // TODO: implement testnet difficulty rule check - return r; // don't worry about difficulty on testnet for now -#endif - // TODO: fix difficulty target check for Litecoin // if (r && (block->height % BLOCK_DIFFICULTY_INTERVAL) == 0) { // // target is in "compact" format, where the most significant byte is the size of resulting value in bytes, next // // bit is the sign, and the remaining 23bits is the value after having been right shifted by (size - 3)*8 bits diff --git a/BRMerkleBlock.h b/BRMerkleBlock.h index bef958cb6..d99928515 100644 --- a/BRMerkleBlock.h +++ b/BRMerkleBlock.h @@ -60,6 +60,9 @@ typedef struct { // returns a newly allocated merkle block struct that must be freed by calling BRMerkleBlockFree() BRMerkleBlock *BRMerkleBlockNew(void); +// returns a deep copy of block and that must be freed by calling BRMerkleBlockFree() +BRMerkleBlock *BRMerkleBlockCopy(const BRMerkleBlock *block); + // buf must contain either a serialized merkleblock or header // returns a merkle block struct that must be freed by calling BRMerkleBlockFree() BRMerkleBlock *BRMerkleBlockParse(const uint8_t *buf, size_t bufLen); diff --git a/BRPeer.c b/BRPeer.c index c69d17a9e..6be91b701 100644 --- a/BRPeer.c +++ b/BRPeer.c @@ -43,11 +43,6 @@ #include #include -#if LITECOIN_TESTNET -#define MAGIC_NUMBER 0xf1c8d2fd -#else -#define MAGIC_NUMBER 0xdbb6c0fb -#endif #define HEADER_LENGTH 24 #define MAX_MSG_LENGTH 0x02000000 #define MAX_GETDATA_HASHES 50000 @@ -95,6 +90,7 @@ typedef enum { typedef struct { BRPeer peer; // superstruct on top of BRPeer + uint32_t magicNumber; char host[INET6_ADDRSTRLEN]; BRPeerStatus status; int waitingForNetwork; @@ -226,7 +222,8 @@ static int _BRPeerAcceptVersionMessage(BRPeer *peer, const uint8_t *msg, size_t off += strLen; ctx->lastblock = UInt32GetLE(&msg[off]); off += sizeof(uint32_t); - peer_log(peer, "got version %"PRIu32", useragent:\"%s\"", ctx->version, ctx->useragent); + peer_log(peer, "got version %"PRIu32", services %"PRIx64", useragent:\"%s\"", ctx->version, peer->services, + ctx->useragent); BRPeerSendVerackMessage(peer); } } @@ -416,7 +413,7 @@ static int _BRPeerAcceptTxMessage(BRPeer *peer, const uint8_t *msg, size_t msgLe } else { txHash = tx->txHash; - peer_log(peer, "got tx: %s", u256_hex_encode(txHash)); + peer_log(peer, "got tx: %s", u256hex(txHash)); if (ctx->relayedTx) { ctx->relayedTx(ctx->info, tx); @@ -485,7 +482,7 @@ static int _BRPeerAcceptHeadersMessage(BRPeer *peer, const uint8_t *msg, size_t BRMerkleBlock *block = BRMerkleBlockParse(&msg[off + 81*i], 81); if (! BRMerkleBlockIsValid(block, (uint32_t)now)) { - peer_log(peer, "invalid block header: %s", u256_hex_encode(block->blockHash)); + peer_log(peer, "invalid block header: %s", u256hex(block->blockHash)); BRMerkleBlockFree(block); r = 0; } @@ -701,7 +698,7 @@ static int _BRPeerAcceptMerkleblockMessage(BRPeer *peer, const uint8_t *msg, siz r = 0; } else if (! BRMerkleBlockIsValid(block, (uint32_t)time(NULL))) { - peer_log(peer, "invalid merkleblock: %s", u256_hex_encode(block->blockHash)); + peer_log(peer, "invalid merkleblock: %s", u256hex(block->blockHash)); BRMerkleBlockFree(block); block = NULL; r = 0; @@ -781,8 +778,7 @@ static int _BRPeerAcceptRejectMessage(BRPeer *peer, const uint8_t *msg, size_t m off += hashLen; if (! UInt256IsZero(txHash)) { - peer_log(peer, "rejected %s code: 0x%x reason: \"%s\" txid: %s", type, code, reason, - u256_hex_encode(txHash)); + peer_log(peer, "rejected %s code: 0x%x reason: \"%s\" txid: %s", type, code, reason, u256hex(txHash)); if (ctx->rejectedTx) ctx->rejectedTx(ctx->info, txHash, code); } else peer_log(peer, "rejected %s code: 0x%x reason: \"%s\"", type, code, reason); @@ -817,8 +813,8 @@ static int _BRPeerAcceptMessage(BRPeer *peer, const uint8_t *msg, size_t msgLen, int r = 1; if (ctx->currentBlock && strncmp(MSG_TX, type, 12) != 0) { // if we receive a non-tx message, merkleblock is done - peer_log(peer, "incomplete merkleblock %s, expected %zu more tx, got %s", - u256_hex_encode(ctx->currentBlock->blockHash), array_count(ctx->currentBlockTxHashes), type); + peer_log(peer, "incomplete merkleblock %s, expected %zu more tx, got %s", u256hex(ctx->currentBlock->blockHash), + array_count(ctx->currentBlockTxHashes), type); array_clear(ctx->currentBlockTxHashes); ctx->currentBlock = NULL; r = 0; @@ -958,7 +954,7 @@ static void *_peerThreadRoutine(void *arg) ctx->mempoolTime = DBL_MAX; } - while (sizeof(uint32_t) <= len && UInt32GetLE(header) != MAGIC_NUMBER) { + while (sizeof(uint32_t) <= len && UInt32GetLE(header) != ctx->magicNumber) { memmove(header, &header[1], --len); // consume one byte at a time until we find the magic number } @@ -1009,8 +1005,7 @@ static void *_peerThreadRoutine(void *arg) if (UInt32GetLE(&hash) != checksum) { // verify checksum peer_log(peer, "error reading %s, invalid checksum %x, expected %x, payload length:%"PRIu32 - ", SHA256_2:%s", type, UInt32GetLE(&hash), checksum, msgLen, - u256_hex_encode(hash)); + ", SHA256_2:%s", type, UInt32GetLE(&hash), checksum, msgLen, u256hex(hash)); error = EPROTO; } else if (! _BRPeerAcceptMessage(peer, payload, msgLen, type)) error = EPROTO; @@ -1049,11 +1044,12 @@ static void _dummyThreadCleanup(void *info) } // returns a newly allocated BRPeer struct that must be freed by calling BRPeerFree() -BRPeer *BRPeerNew(void) +BRPeer *BRPeerNew(uint32_t magicNumber) { BRPeerContext *ctx = calloc(1, sizeof(*ctx)); assert(ctx != NULL); + ctx->magicNumber = magicNumber; array_new(ctx->useragent, 40); array_new(ctx->knownBlockHashes, 10); array_new(ctx->currentBlockTxHashes, 10); @@ -1262,7 +1258,7 @@ void BRPeerSendMessage(BRPeer *peer, const uint8_t *msg, size_t msgLen, const ch struct timeval tv; int socket, error = 0; - UInt32SetLE(&buf[off], MAGIC_NUMBER); + UInt32SetLE(&buf[off], ctx->magicNumber); off += sizeof(uint32_t); strncpy((char *)&buf[off], type, 12); off += 12; @@ -1315,7 +1311,7 @@ void BRPeerSendVersionMessage(BRPeer *peer) off += sizeof(uint64_t); UInt128Set(&msg[off], LOCAL_HOST); // IPv4 mapped IPv6 header off += sizeof(UInt128); - UInt16SetBE(&msg[off], STANDARD_PORT); + UInt16SetBE(&msg[off], peer->port); off += sizeof(uint16_t); ctx->nonce = ((uint64_t)BRRand(0) << 32) | (uint64_t)BRRand(0); // random nonce UInt64SetLE(&msg[off], ctx->nonce); @@ -1397,9 +1393,8 @@ void BRPeerSendGetheaders(BRPeer *peer, const UInt256 locators[], size_t locator off += sizeof(UInt256); if (locatorsCount > 0) { - peer_log(peer, "calling getheaders with %zu locators: [%s,%s %s]", locatorsCount, - u256_hex_encode(locators[0]), (locatorsCount > 2 ? " ...," : ""), - (locatorsCount > 1 ? u256_hex_encode(locators[locatorsCount - 1]) : "")); + peer_log(peer, "calling getheaders with %zu locators: [%s,%s %s]", locatorsCount, u256hex(locators[0]), + (locatorsCount > 2 ? " ...," : ""), (locatorsCount > 1 ? u256hex(locators[locatorsCount - 1]) : "")); BRPeerSendMessage(peer, msg, off, MSG_GETHEADERS); } } @@ -1423,9 +1418,8 @@ void BRPeerSendGetblocks(BRPeer *peer, const UInt256 locators[], size_t locators off += sizeof(UInt256); if (locatorsCount > 0) { - peer_log(peer, "calling getblocks with %zu locators: [%s,%s %s]", locatorsCount, - u256_hex_encode(locators[0]), (locatorsCount > 2 ? " ...," : ""), - (locatorsCount > 1 ? u256_hex_encode(locators[locatorsCount - 1]) : "")); + peer_log(peer, "calling getblocks with %zu locators: [%s,%s %s]", locatorsCount, u256hex(locators[0]), + (locatorsCount > 2 ? " ...," : ""), (locatorsCount > 1 ? u256hex(locators[locatorsCount - 1]) : "")); BRPeerSendMessage(peer, msg, off, MSG_GETBLOCKS); } } diff --git a/BRPeer.h b/BRPeer.h index 7d3759bb6..5f6a44b11 100644 --- a/BRPeer.h +++ b/BRPeer.h @@ -52,17 +52,11 @@ extern "C" { #endif -#if LITECOIN_TESTNET -#define STANDARD_PORT 19335 -#else -#define STANDARD_PORT 9333 -#endif - #define SERVICES_NODE_NETWORK 0x01 // services value indicating a node carries full blocks, not just headers #define SERVICES_NODE_BLOOM 0x04 // BIP111: https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki #define SERVICES_NODE_BCASH 0x20 // https://github.com/Bitcoin-UAHF/spec/blob/master/uahf-technical-spec.md -#define BR_VERSION "175" +#define BR_VERSION "2.1" #define USER_AGENT "/loaf-android:" BR_VERSION "/" // explanation of message types at: https://en.bitcoin.it/wiki/Protocol_specification @@ -114,7 +108,7 @@ typedef struct { // NOTE: BRPeer functions are not thread-safe // returns a newly allocated BRPeer struct that must be freed by calling BRPeerFree() -BRPeer *BRPeerNew(void); +BRPeer *BRPeerNew(uint32_t magicNumber); // info is a void pointer that will be passed along with each callback call // void connected(void *) - called when peer handshake completes successfully diff --git a/BRPeerManager.c b/BRPeerManager.c index fde60d0d9..c1502ab89 100644 --- a/BRPeerManager.c +++ b/BRPeerManager.c @@ -41,64 +41,10 @@ #define PROTOCOL_TIMEOUT 20.0 #define MAX_CONNECT_FAILURES 20 // notify user of network problems after this many connect failures in a row -#define CHECKPOINT_COUNT (sizeof(checkpoint_array)/sizeof(*checkpoint_array)) -#define DNS_SEEDS_COUNT (sizeof(dns_seeds)/sizeof(*dns_seeds)) -#define GENESIS_BLOCK_HASH (UInt256Reverse(u256_hex_decode(checkpoint_array[0].hash))) #define PEER_FLAG_SYNCED 0x01 #define PEER_FLAG_NEEDSUPDATE 0x02 -#if LITECOIN_TESTNET - -static const struct { uint32_t height; const char *hash; uint32_t timestamp; uint32_t target; } checkpoint_array[] = { - { 0, "4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0", 1486949366, 0x1e0ffff0 } -}; - -static const char *dns_seeds[] = { - "testnet-seed.ltc.xurious.com.", - "seed-b.litecoin.loshan.co.uk.", - "dnsseed-testnet.thrasher.io." -}; - -#else // main net - -// blockchain checkpoints - these are also used as starting points for partial chain downloads, so they need to be at -// difficulty transition boundaries in order to verify the block difficulty at the immediately following transition -static const struct { uint32_t height; const char *hash; uint32_t timestamp; uint32_t target; } checkpoint_array[] = { - { 0, "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2", 1317972665, 0x1e0ffff0 }, - { 20160, "633036c8df655531c2449b2d09b264cc0b49d945a89be23fd3c1a97361ca198c", 1319798300, 0x1d055262 }, - { 40320, "d148cdd2cf44069cef4b63f0feaf30a8d291ca9ea9ba7e83f226b9738c1d5e9c", 1322522019, 0x1d018053 }, - { 60480, "3250f0a560d55f039c34bfaee1b71297aa5104ac6641778f9a87d73232d12c6c", 1325540574, 0x1d00e848 }, - { 80640, "bedc0a090b740b1902d870aeb6caa89040a24e7d670d46f8ef035fd9d2e9ce80", 1328779944, 0x1d00ab92 }, - { 100800, "7b0b620d15f781faaaa73b43607a49d5becb2b803ef19b4010014646cc177a61", 1331873688, 0x1d00ae9f }, - { 120960, "dbd6249f30e5690890bc03dabcc0a526c46adcde572be06af4075b6ea28aa251", 1334881566, 0x1d009e48 }, - { 141120, "5d5e15a45cecf2b9528e36e63c407167423a2f9963a96bbce3b67b75fd10be2a", 1338009318, 0x1d00d6a6 }, - { 161280, "f595c754d0abcfe3616573bfabee01b230ec0ea6b2f2894c40214ea23d772b6c", 1340918301, 0x1d008881 }, - { 181440, "d7fa3152959f3c25e33edf825f7cbef75ee651d5f9183cc4ed8d19d57b8f35a4", 1343534530, 0x1c1cd430 }, - { 201600, "d481df8e8ce144fca9ae6b3157cc706e903c6ea161a13d2c421270354a02d6d0", 1346567025, 0x1c1c89e8 }, - { 282240, "8932095fba44bd6860fd71745c0dca908769221a47166ab1fb442b6cefcd53fb", 1358801720, 0x1c0ced21 }, - { 342720, "33f62e026a202be550e8a9df37d638d38991553544e279cb264123378bf46042", 1367113967, 0x1c0095a5 }, - { 383040, "5c0a443361c1356796a7db472c69433b6ce6108d61e4403fd9a9d91e01009ce3", 1372971948, 0x1b481262 }, - { 443520, "37d668803ed1efc24ffab4a2a90da9ac92679acf68370d7570f042c2bd6d651b", 1382034998, 0x1b3f864f }, - { 504000, "97db0624d3d5137bc085f0d731607314972bb4124b85b73420ef9aa5fc10d640", 1390892377, 0x1b1aa868 }, - { 564480, "c876276bf12754c2b265787d9e7ab83d429e59761dc63057f728529018db7834", 1399724592, 0x1b099dce }, - { 624960, "ccac71fafe98107b81ac3e0eed41190e4d47600962c93c49db8843b53f760bda", 1408389228, 0x1b02552d }, - { 685440, "29d2328990dda4c4870846d4e3d573785452bed68e6013930a83fc8d5fe89b09", 1417289378, 0x1b01473b }, - { 745920, "04809a35ff6e5054e21d14582072605b812b7d4ae11d3450e7c03a7237e1d35d", 1426441593, 0x1b019b8c }, - { 806400, "e2363e8b3e8f237b9b1bfc1c72ede80fef2c7bd1aabcd78afed82065a194b960", 1435516150, 0x1b019268 }, - { 846720, "6f5d94d7cfd01f1dbf4aa631b987f8e2ec9d0c57720604787b816bafe34192a8", 1441561050, 0x1b0187a3 }, - { 901152, "cfccdf8e3830ae4879e910051ac3dc583b4fb45b83be3a38019e5d9326dfa223", 1449698771, 0x1b015b0e }, - { 953568, "e46e01cf1239cffa69408ac162d517bac5a4899972e0328fd0ba4d93e8ad3764", 1457542869, 0x1b013c91 }, - { 1058400, "76ce37c66d449a4ffbfc35674cf932da701066a001dc223754f9250dd2bdbc62", 1473296285, 0x1b013ca7 }, - { 1260000, "85a22b528d805bf7a641d1d7c6d96ef5054beda3dcab6be7b83f2e3df24b33a8", 1502976600, 0x1a25a0d3 }, - { 1411200, "92c85b76f3d4bffca76b23717e4eb1b667c77c96fd52d4dd5dd843bbee64cd73", 1524838967, 0x1a0203a7 }, - { 1260000, "85a22b528d805bf7a641d1d7c6d96ef5054beda3dcab6be7b83f2e3df24b33a8", 1502976600, 0x1a25a0d3 } -}; - -static const char *dns_seeds[] = { - "dnsseed.litecoinpool.org.", "seed-a.litecoin.loshan.co.uk.", "dnsseed.thrasher.io.", - "dnsseed.koin-project.com.", "dnsseed.litecointools.com." -}; -#endif +#define genesis_block_hash(params) UInt256Reverse((params)->checkpoints[0].hash) typedef struct { BRPeerManager *manager; @@ -221,6 +167,7 @@ inline static int _BRBlockHeightEq(const void *block, const void *otherBlock) } struct BRPeerManagerStruct { + const BRChainParams *params; BRWallet *wallet; int isConnected, connectFailureCount, misbehavinCount, dnsThreadCount, maxConnectCount; BRPeer *peers, *downloadPeer, fixedPeer, **connectedPeers; @@ -307,7 +254,7 @@ static size_t _BRPeerManagerBlockLocators(BRPeerManager *manager, UInt256 locato } } - if (locators && i < locatorsCount) locators[i] = GENESIS_BLOCK_HASH; + if (locators && i < locatorsCount) locators[i] = genesis_block_hash(manager->params); return ++i; } @@ -547,26 +494,30 @@ static void _requestUnrelayedTxGetdataDone(void *info, int success) // don't remove transactions until we're connected to maxConnectCount peers, and all peers have finished // relaying their mempools if (count >= manager->maxConnectCount) { + UInt256 hash; size_t txCount = BRWalletTxUnconfirmedBefore(manager->wallet, NULL, 0, TX_UNCONFIRMED); - BRTransaction *tx[(txCount < 10000) ? txCount : 10000]; + BRTransaction *tx[(txCount*sizeof(BRTransaction *) <= 0x1000) ? txCount : 0x1000/sizeof(BRTransaction *)]; txCount = BRWalletTxUnconfirmedBefore(manager->wallet, tx, sizeof(tx)/sizeof(*tx), TX_UNCONFIRMED); - for (size_t i = 0; i < txCount; i++) { + for (size_t i = txCount; i > 0; i--) { + hash = tx[i - 1]->txHash; isPublishing = 0; for (size_t j = array_count(manager->publishedTx); ! isPublishing && j > 0; j--) { - if (BRTransactionEq(manager->publishedTx[j - 1].tx, tx[i]) && + if (BRTransactionEq(manager->publishedTx[j - 1].tx, tx[i - 1]) && manager->publishedTx[j - 1].callback != NULL) isPublishing = 1; } - if (! isPublishing && _BRTxPeerListCount(manager->txRelays, tx[i]->txHash) == 0 && - _BRTxPeerListCount(manager->txRequests, tx[i]->txHash) == 0) { - BRWalletRemoveTransaction(manager->wallet, tx[i]->txHash); + if (! isPublishing && _BRTxPeerListCount(manager->txRelays, hash) == 0 && + _BRTxPeerListCount(manager->txRequests, hash) == 0) { + peer_log(peer, "removing tx unconfirmed at: %d, txHash: %s", manager->lastBlock->height, u256hex(hash)); + assert(tx[i - 1]->blockHeight == TX_UNCONFIRMED); + BRWalletRemoveTransaction(manager->wallet, hash); } - else if (! isPublishing && _BRTxPeerListCount(manager->txRelays, tx[i]->txHash) < manager->maxConnectCount){ + else if (! isPublishing && _BRTxPeerListCount(manager->txRelays, hash) < manager->maxConnectCount) { // set timestamp 0 to mark as unverified - _BRPeerManagerUpdateTx(manager, &tx[i]->txHash, 1, TX_UNCONFIRMED, 0); + _BRPeerManagerUpdateTx(manager, &hash, 1, TX_UNCONFIRMED, 0); } } } @@ -733,7 +684,7 @@ static void *_findPeersThreadRoutine(void *arg) for (addr = addrList; addr && ! UInt128IsZero(*addr); addr++) { age = 24*60*60 + BRRand(2*24*60*60); // add between 1 and 3 days - array_add(manager->peers, ((BRPeer) { *addr, STANDARD_PORT, services, now - age, 0 })); + array_add(manager->peers, ((BRPeer) { *addr, manager->params->standardPort, services, now - age, 0 })); } manager->dnsThreadCount--; @@ -746,7 +697,7 @@ static void *_findPeersThreadRoutine(void *arg) // DNS peer discovery static void _BRPeerManagerFindPeers(BRPeerManager *manager) { - static const uint64_t services = SERVICES_NODE_NETWORK | SERVICES_NODE_BLOOM; + uint64_t services = SERVICES_NODE_NETWORK | SERVICES_NODE_BLOOM | manager->params->services; time_t now = time(NULL); struct timespec ts; pthread_t thread; @@ -761,18 +712,18 @@ static void _BRPeerManagerFindPeers(BRPeerManager *manager) manager->peers[0].timestamp = now; } else { - for (size_t i = 1; i < DNS_SEEDS_COUNT; i++) { + for (size_t i = 1; manager->params->dnsSeeds[i]; i++) { info = calloc(1, sizeof(BRFindPeersInfo)); assert(info != NULL); info->manager = manager; - info->hostname = dns_seeds[i]; + info->hostname = manager->params->dnsSeeds[i]; info->services = services; if (pthread_attr_init(&attr) == 0 && pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0 && pthread_create(&thread, &attr, _findPeersThreadRoutine, info) == 0) manager->dnsThreadCount++; } - for (addr = addrList = _addressLookup(dns_seeds[0]); addr && ! UInt128IsZero(*addr); addr++) { - array_add(manager->peers, ((BRPeer) { *addr, STANDARD_PORT, services, now, 0 })); + for (addr = addrList = _addressLookup(manager->params->dnsSeeds[0]); addr && ! UInt128IsZero(*addr); addr++) { + array_add(manager->peers, ((BRPeer) { *addr, manager->params->standardPort, services, now, 0 })); } if (addrList) free(addrList); @@ -800,7 +751,11 @@ static void _peerConnected(void *info) if (peer->timestamp > now + 2*60*60 || peer->timestamp < now - 2*60*60) peer->timestamp = now; // sanity check // TODO: XXX does this work with 0.11 pruned nodes? - if (! (peer->services & SERVICES_NODE_NETWORK)) { + if ((peer->services & manager->params->services) != manager->params->services) { + peer_log(peer, "unsupported node type"); + BRPeerDisconnect(peer); + } + else if ((peer->services & SERVICES_NODE_NETWORK) != SERVICES_NODE_NETWORK) { peer_log(peer, "node doesn't carry full blocks"); BRPeerDisconnect(peer); } @@ -808,11 +763,7 @@ static void _peerConnected(void *info) peer_log(peer, "node isn't synced"); BRPeerDisconnect(peer); } - else if ((peer->services & SERVICES_NODE_BCASH) == SERVICES_NODE_BCASH) { - peer_log(peer, "b-cash nodes not supported"); - BRPeerDisconnect(peer); - } - else if (BRPeerVersion(peer) >= 70011 && ! (peer->services & SERVICES_NODE_BLOOM)) { + else if (BRPeerVersion(peer) >= 70011 && (peer->services & SERVICES_NODE_BLOOM) != SERVICES_NODE_BLOOM) { peer_log(peer, "node doesn't support SPV mode"); BRPeerDisconnect(peer); } @@ -841,7 +792,11 @@ static void _peerConnected(void *info) BRPeerLastBlock(p) > BRPeerLastBlock(peer)) peer = p; } - if (manager->downloadPeer) BRPeerDisconnect(manager->downloadPeer); + if (manager->downloadPeer) { + peer_log(peer, "selecting new download peer with higher reported lastblock"); + BRPeerDisconnect(manager->downloadPeer); + } + manager->downloadPeer = peer; manager->isConnected = 1; manager->estimatedHeight = BRPeerLastBlock(peer); @@ -998,7 +953,7 @@ static void _peerRelayedTx(void *info, BRTransaction *tx) size_t relayCount = 0; pthread_mutex_lock(&manager->lock); - peer_log(peer, "relayed tx: %s", u256_hex_encode(tx->txHash)); + peer_log(peer, "relayed tx: %s", u256hex(tx->txHash)); for (size_t i = array_count(manager->publishedTx); i > 0; i--) { // see if tx is in list of published tx if (UInt256Eq(manager->publishedTxHashes[i - 1], tx->txHash)) { @@ -1082,7 +1037,7 @@ static void _peerHasTx(void *info, UInt256 txHash) pthread_mutex_lock(&manager->lock); tx = BRWalletTransactionForHash(manager->wallet, txHash); - peer_log(peer, "has tx: %s", u256_hex_encode(txHash)); + peer_log(peer, "has tx: %s", u256hex(txHash)); for (size_t i = array_count(manager->publishedTx); i > 0; i--) { // see if tx is in list of published tx if (UInt256Eq(manager->publishedTxHashes[i - 1], txHash)) { @@ -1133,7 +1088,7 @@ static void _peerRejectedTx(void *info, UInt256 txHash, uint8_t code) BRTransaction *tx, *t; pthread_mutex_lock(&manager->lock); - peer_log(peer, "rejected tx: %s", u256_hex_encode(txHash)); + peer_log(peer, "rejected tx: %s", u256hex(txHash)); tx = BRWalletTransactionForHash(manager->wallet, txHash); _BRTxPeerListRemovePeer(manager->txRequests, txHash, peer); @@ -1162,11 +1117,12 @@ static void _peerRejectedTx(void *info, UInt256 txHash, uint8_t code) static int _BRPeerManagerVerifyBlock(BRPeerManager *manager, BRMerkleBlock *block, BRMerkleBlock *prev, BRPeer *peer) { - uint32_t transitionTime = 0; int r = 1; + if (! prev || ! UInt256Eq(block->prevBlock, prev->blockHash) || block->height != prev->height + 1) r = 0; + // check if we hit a difficulty transition, and find previous transition time - if ((block->height % BLOCK_DIFFICULTY_INTERVAL) == 0) { + if (r && (block->height % BLOCK_DIFFICULTY_INTERVAL) == 0) { BRMerkleBlock *b = block; UInt256 prevBlock; @@ -1175,14 +1131,10 @@ static int _BRPeerManagerVerifyBlock(BRPeerManager *manager, BRMerkleBlock *bloc } if (! b) { - peer_log(peer, "missing previous difficulty tansition time, can't verify blockHash: %s", - u256_hex_encode(block->blockHash)); + peer_log(peer, "missing previous difficulty tansition, can't verify block: %s", u256hex(block->blockHash)); r = 0; } - else { - transitionTime = b->timestamp; - prevBlock = b->prevBlock; - } + else prevBlock = b->prevBlock; while (b) { // free up some memory b = BRSetGet(manager->blocks, &prevBlock); @@ -1196,9 +1148,9 @@ static int _BRPeerManagerVerifyBlock(BRPeerManager *manager, BRMerkleBlock *bloc } // verify block difficulty - if (r && ! BRMerkleBlockVerifyDifficulty(block, prev, transitionTime)) { + if (r && ! manager->params->verifyDifficulty(block, manager->blocks)) { peer_log(peer, "relayed block with invalid difficulty target %x, blockHash: %s", block->target, - u256_hex_encode(block->blockHash)); + u256hex(block->blockHash)); r = 0; } @@ -1208,8 +1160,7 @@ static int _BRPeerManagerVerifyBlock(BRPeerManager *manager, BRMerkleBlock *bloc // verify blockchain checkpoints if (checkpoint && ! BRMerkleBlockEq(block, checkpoint)) { peer_log(peer, "relayed a block that differs from the checkpoint at height %"PRIu32", blockHash: %s, " - "expected: %s", block->height, u256_hex_encode(block->blockHash), - u256_hex_encode(checkpoint->blockHash)); + "expected: %s", block->height, u256hex(block->blockHash), u256hex(checkpoint->blockHash)); r = 0; } } @@ -1280,8 +1231,8 @@ static void _peerRelayedBlock(void *info, BRMerkleBlock *block) } else if (! prev) { // block is an orphan peer_log(peer, "relayed orphan block %s, previous %s, last block is %s, height %"PRIu32, - u256_hex_encode(block->blockHash), u256_hex_encode(block->prevBlock), - u256_hex_encode(manager->lastBlock->blockHash), manager->lastBlock->height); + u256hex(block->blockHash), u256hex(block->prevBlock), u256hex(manager->lastBlock->blockHash), + manager->lastBlock->height); if (block->timestamp + 7*24*60*60 < time(NULL)) { // ignore orphans older than one week ago BRMerkleBlockFree(block); @@ -1358,9 +1309,9 @@ static void _peerRelayedBlock(void *info, BRMerkleBlock *block) BRSetAdd(manager->orphans, block); // mark as orphan til we're caught up manager->lastOrphan = block; } - else if (block->height <= checkpoint_array[CHECKPOINT_COUNT - 1].height) { // fork is older than last checkpoint + else if (block->height <= manager->params->checkpoints[manager->params->checkpointsCount - 1].height) { // old fork peer_log(peer, "ignoring block on fork older than most recent checkpoint, block #%"PRIu32", hash: %s", - block->height, u256_hex_encode(block->blockHash)); + block->height, u256hex(block->blockHash)); BRMerkleBlockFree(block); block = NULL; } @@ -1422,6 +1373,7 @@ static void _peerRelayedBlock(void *info, BRMerkleBlock *block) BRMerkleBlock *saveBlocks[saveCount]; for (i = 0, b = block; b && i < saveCount; i++) { + assert(b->height != BLOCK_UNKNOWN_HEIGHT); // verify all blocks to be saved are in the chain saveBlocks[i] = b; b = BRSetGet(manager->blocks, &b->prevBlock); } @@ -1572,16 +1524,19 @@ static void _dummyThreadCleanup(void *info) } // returns a newly allocated BRPeerManager struct that must be freed by calling BRPeerManagerFree() -BRPeerManager *BRPeerManagerNew(BRWallet *wallet, uint32_t earliestKeyTime, BRMerkleBlock *blocks[], size_t blocksCount, - const BRPeer peers[], size_t peersCount) +BRPeerManager *BRPeerManagerNew(const BRChainParams *params, BRWallet *wallet, uint32_t earliestKeyTime, + BRMerkleBlock *blocks[], size_t blocksCount, const BRPeer peers[], size_t peersCount) { BRPeerManager *manager = calloc(1, sizeof(*manager)); BRMerkleBlock orphan, *block = NULL; assert(manager != NULL); + assert(params != NULL); + assert(params->standardPort != 0); assert(wallet != NULL); assert(blocks != NULL || blocksCount == 0); assert(peers != NULL || peersCount == 0); + manager->params = params; manager->wallet = wallet; manager->earliestKeyTime = earliestKeyTime; manager->averageTxPerBlock = 1400; @@ -1594,12 +1549,12 @@ BRPeerManager *BRPeerManagerNew(BRWallet *wallet, uint32_t earliestKeyTime, BRMe manager->orphans = BRSetNew(_BRPrevBlockHash, _BRPrevBlockEq, blocksCount); // orphans are indexed by prevBlock manager->checkpoints = BRSetNew(_BRBlockHeightHash, _BRBlockHeightEq, 100); // checkpoints are indexed by height - for (size_t i = 0; i < CHECKPOINT_COUNT; i++) { + for (size_t i = 0; i < manager->params->checkpointsCount; i++) { block = BRMerkleBlockNew(); - block->height = checkpoint_array[i].height; - block->blockHash = UInt256Reverse(u256_hex_decode(checkpoint_array[i].hash)); - block->timestamp = checkpoint_array[i].timestamp; - block->target = checkpoint_array[i].target; + block->height = manager->params->checkpoints[i].height; + block->blockHash = UInt256Reverse(manager->params->checkpoints[i].hash); + block->timestamp = manager->params->checkpoints[i].timestamp; + block->target = manager->params->checkpoints[i].target; BRSetAdd(manager->checkpoints, block); BRSetAdd(manager->blocks, block); if (i == 0 || block->timestamp + 7*24*60*60 < manager->earliestKeyTime) manager->lastBlock = block; @@ -1677,16 +1632,22 @@ void BRPeerManagerSetFixedPeer(BRPeerManager *manager, UInt128 address, uint16_t pthread_mutex_unlock(&manager->lock); } -// true if currently connected to at least one peer -int BRPeerManagerIsConnected(BRPeerManager *manager) +// current connect status +BRPeerStatus BRPeerManagerConnectStatus(BRPeerManager *manager) { - int isConnected; + BRPeerStatus status = BRPeerStatusDisconnected; assert(manager != NULL); pthread_mutex_lock(&manager->lock); - isConnected = manager->isConnected; + if (manager->isConnected != 0) status = BRPeerStatusConnected; + + for (size_t i = array_count(manager->connectedPeers); i > 0 && status == BRPeerStatusDisconnected; i--) { + if (BRPeerConnectStatus(manager->connectedPeers[i - 1]) == BRPeerStatusDisconnected) continue; + status = BRPeerStatusConnecting; + } + pthread_mutex_unlock(&manager->lock); - return isConnected; + return status; } // connect to bitcoin peer-to-peer network (also call this whenever networkIsReachable() status changes) @@ -1739,7 +1700,7 @@ void BRPeerManagerConnect(BRPeerManager *manager) info = calloc(1, sizeof(*info)); assert(info != NULL); info->manager = manager; - info->peer = BRPeerNew(); + info->peer = BRPeerNew(manager->params->magicNumber); *info->peer = peers[i]; array_rm(peers, i); array_add(manager->connectedPeers, info->peer); @@ -1800,9 +1761,9 @@ void BRPeerManagerRescan(BRPeerManager *manager) if (manager->isConnected) { // start the chain download from the most recent checkpoint that's at least a week older than earliestKeyTime - for (size_t i = CHECKPOINT_COUNT; i > 0; i--) { - if (i - 1 == 0 || checkpoint_array[i - 1].timestamp + 7*24*60*60 < manager->earliestKeyTime) { - UInt256 hash = UInt256Reverse(u256_hex_decode(checkpoint_array[i - 1].hash)); + for (size_t i = manager->params->checkpointsCount; i > 0; i--) { + if (i - 1 == 0 || manager->params->checkpoints[i - 1].timestamp + 7*24*60*60 < manager->earliestKeyTime) { + UInt256 hash = UInt256Reverse(manager->params->checkpoints[i - 1].hash); manager->lastBlock = BRSetGet(manager->blocks, &hash); break; @@ -1895,7 +1856,7 @@ size_t BRPeerManagerPeerCount(BRPeerManager *manager) pthread_mutex_lock(&manager->lock); for (size_t i = array_count(manager->connectedPeers); i > 0; i--) { - if (BRPeerConnectStatus(manager->connectedPeers[i - 1]) == BRPeerStatusConnected) count++; + if (BRPeerConnectStatus(manager->connectedPeers[i - 1]) != BRPeerStatusDisconnected) count++; } pthread_mutex_unlock(&manager->lock); diff --git a/BRPeerManager.h b/BRPeerManager.h index 1322996ce..f01aa0af5 100644 --- a/BRPeerManager.h +++ b/BRPeerManager.h @@ -29,6 +29,7 @@ #include "BRMerkleBlock.h" #include "BRTransaction.h" #include "BRWallet.h" +#include "BRChainParams.h" #include #include @@ -41,8 +42,8 @@ extern "C" { typedef struct BRPeerManagerStruct BRPeerManager; // returns a newly allocated BRPeerManager struct that must be freed by calling BRPeerManagerFree() -BRPeerManager *BRPeerManagerNew(BRWallet *wallet, uint32_t earliestKeyTime, BRMerkleBlock *blocks[], size_t blocksCount, - const BRPeer peers[], size_t peersCount); +BRPeerManager *BRPeerManagerNew(const BRChainParams *params, BRWallet *wallet, uint32_t earliestKeyTime, + BRMerkleBlock *blocks[], size_t blocksCount, const BRPeer peers[], size_t peersCount); // not thread-safe, set callbacks once before calling BRPeerManagerConnect() // info is a void pointer that will be passed along with each callback call @@ -68,8 +69,8 @@ void BRPeerManagerSetCallbacks(BRPeerManager *manager, void *info, // set address to UINT128_ZERO to revert to default behavior void BRPeerManagerSetFixedPeer(BRPeerManager *manager, UInt128 address, uint16_t port); -// true if currently connected to at least one peer -int BRPeerManagerIsConnected(BRPeerManager *manager); +// current connect status +BRPeerStatus BRPeerManagerConnectStatus(BRPeerManager *manager); // connect to bitcoin peer-to-peer network (also call this whenever networkIsReachable() status changes) void BRPeerManagerConnect(BRPeerManager *manager); diff --git a/BRTransaction.c b/BRTransaction.c index 7858473d5..8e0151c8e 100644 --- a/BRTransaction.c +++ b/BRTransaction.c @@ -38,7 +38,7 @@ #define SIGHASH_NONE 0x02 // sign none of the outputs, I don't care where the bitcoins go #define SIGHASH_SINGLE 0x03 // sign one of the outputs, I don't care where the other outputs go #define SIGHASH_ANYONECANPAY 0x80 // let other people add inputs, I don't care where the rest of the bitcoins come from -#define SIGHASH_FORKID 0x40 // use BIP143 digest method (for b-cash signatures) +#define SIGHASH_FORKID 0x40 // use BIP143 digest method (for b-cash/b-gold signatures) // returns a random number less than upperBound, for non-cryptographic use only uint32_t BRRand(uint32_t upperBound) @@ -335,6 +335,32 @@ BRTransaction *BRTransactionNew(void) return tx; } +// returns a deep copy of tx and that must be freed by calling BRTransactionFree() +BRTransaction *BRTransactionCopy(const BRTransaction *tx) +{ + BRTransaction *cpy = BRTransactionNew(); + BRTxInput *inputs = cpy->inputs; + BRTxOutput *outputs = cpy->outputs; + + assert(tx != NULL); + *cpy = *tx; + cpy->inputs = inputs; + cpy->outputs = outputs; + cpy->inCount = cpy->outCount = 0; + + for (size_t i = 0; i < tx->inCount; i++) { + BRTransactionAddInput(cpy, tx->inputs[i].txHash, tx->inputs[i].index, tx->inputs[i].amount, + tx->inputs[i].script, tx->inputs[i].scriptLen, + tx->inputs[i].signature, tx->inputs[i].sigLen, tx->inputs[i].sequence); + } + + for (size_t i = 0; i < tx->outCount; i++) { + BRTransactionAddOutput(cpy, tx->outputs[i].amount, tx->outputs[i].script, tx->outputs[i].scriptLen); + } + + return cpy; +} + // buf must contain a serialized tx // retruns a transaction that must be freed by calling BRTransactionFree() BRTransaction *BRTransactionParse(const uint8_t *buf, size_t bufLen) @@ -507,7 +533,7 @@ int BRTransactionIsSigned(const BRTransaction *tx) } // adds signatures to any inputs with NULL signatures that can be signed with any keys -// forkId is 0 for bitcoin, 0x40 for b-cash +// forkId is 0 for bitcoin, 0x40 for b-cash, 0x4f for b-gold // returns true if tx is signed int BRTransactionSign(BRTransaction *tx, int forkId, BRKey keys[], size_t keysCount) { diff --git a/BRTransaction.h b/BRTransaction.h index 23c1e7458..636a1fd5a 100644 --- a/BRTransaction.h +++ b/BRTransaction.h @@ -57,7 +57,7 @@ uint32_t BRRand(uint32_t upperBound); typedef struct { UInt256 txHash; uint32_t index; - char address[36]; + char address[75]; uint64_t amount; uint8_t *script; size_t scriptLen; @@ -71,7 +71,7 @@ void BRTxInputSetScript(BRTxInput *input, const uint8_t *script, size_t scriptLe void BRTxInputSetSignature(BRTxInput *input, const uint8_t *signature, size_t sigLen); typedef struct { - char address[36]; + char address[75]; uint64_t amount; uint8_t *script; size_t scriptLen; @@ -98,6 +98,9 @@ typedef struct { // returns a newly allocated empty transaction that must be freed by calling BRTransactionFree() BRTransaction *BRTransactionNew(void); +// returns a deep copy of tx and that must be freed by calling BRTransactionFree() +BRTransaction *BRTransactionCopy(const BRTransaction *tx); + // buf must contain a serialized tx // retruns a transaction that must be freed by calling BRTransactionFree() BRTransaction *BRTransactionParse(const uint8_t *buf, size_t bufLen); @@ -127,7 +130,7 @@ uint64_t BRTransactionStandardFee(const BRTransaction *tx); int BRTransactionIsSigned(const BRTransaction *tx); // adds signatures to any inputs with NULL signatures that can be signed with any keys -// forkId is 0 for bitcoin, 0x40 for b-cash +// forkId is 0 for bitcoin, 0x40 for b-cash, 0x4f for b-gold // returns true if tx is signed int BRTransactionSign(BRTransaction *tx, int forkId, BRKey keys[], size_t keysCount); diff --git a/BRWallet.c b/BRWallet.c index 2da84b467..74ceeaa92 100644 --- a/BRWallet.c +++ b/BRWallet.c @@ -201,6 +201,7 @@ static void _BRWalletUpdateBalance(BRWallet *wallet) tx->lockTime > wallet->blockHeight + 1) isPending = 1; // future lockTime if (tx->inputs[j].sequence < UINT32_MAX && tx->lockTime > now) isPending = 1; // future lockTime if (BRSetContains(wallet->pendingTx, &tx->inputs[j].txHash)) isPending = 1; // check for pending inputs + // TODO: XXX handle BIP68 check lock time verify rules } if (isPending) { @@ -812,9 +813,9 @@ void BRWalletRemoveTransaction(BRWallet *wallet, UInt256 txHash) } } - BRTransactionFree(tx); if (wallet->balanceChanged) wallet->balanceChanged(wallet->callbackInfo, wallet->balance); if (wallet->txDeleted) wallet->txDeleted(wallet->callbackInfo, txHash, notifyUser, recommendRescan); + BRTransactionFree(tx); } array_free(hashes); diff --git a/module.modulemap b/module.modulemap index b8c5ea875..1e05dfff0 100644 --- a/module.modulemap +++ b/module.modulemap @@ -9,6 +9,7 @@ module BRCore [system] [extern_c] { header "BRPeer.h" header "BRCrypto.h" header "BRBase58.h" + header "BRBech32.h" header "BRKey.h" header "BRBIP38Key.h" header "BRBIP39Mnemonic.h" @@ -18,5 +19,6 @@ module BRCore [system] [extern_c] { header "BRAddress.h" header "BRWallet.h" header "BRPeerManager.h" + header "BRChainParams.h" export * } diff --git a/test.c b/test.c index f6042edfa..6c1787b89 100644 --- a/test.c +++ b/test.c @@ -30,14 +30,17 @@ #include "BRBIP38Key.h" #include "BRAddress.h" #include "BRBase58.h" +#include "BRBech32.h" #include "BRBIP39Mnemonic.h" #include "BRBIP39WordsEn.h" #include "BRPeer.h" #include "BRPeerManager.h" +#include "BRChainParams.h" #include "BRPaymentProtocol.h" #include "BRInt.h" #include "BRArray.h" #include "BRSet.h" +#include "BRTransaction.h" #include #include #include @@ -57,6 +60,12 @@ #define _va_rest(first, ...) __VA_ARGS__ #endif +#if LITECOIN_TESTNET +#define BR_CHAIN_PARAMS BRTestNetParams +#else +#define BR_CHAIN_PARAMS BRMainNetParams +#endif + int BRIntsTests() { // test endianess @@ -217,12 +226,12 @@ int BRBase58Tests() uint8_t buf1[BRBase58Decode(NULL, 0, s)]; size_t len1 = BRBase58Decode(buf1, sizeof(buf1), s); - if (len1 != 0) r = 0, fprintf(stderr, "***FAILED*** %s: Base58Decode() test 1\n", __func__); + if (len1 != 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRBase58Decode() test 1\n", __func__); uint8_t buf2[BRBase58Decode(NULL, 0, "")]; size_t len2 = BRBase58Decode(buf2, sizeof(buf2), ""); - if (len2 != 0) r = 0, fprintf(stderr, "***FAILED*** %s: Base58Decode() test 2\n", __func__); + if (len2 != 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRBase58Decode() test 2\n", __func__); s = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -231,7 +240,7 @@ int BRBase58Tests() char str3[BRBase58Encode(NULL, 0, buf3, len3)]; BRBase58Encode(str3, sizeof(str3), buf3, len3); - if (strcmp(str3, s) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: Base58Decode() test 3\n", __func__); + if (strcmp(str3, s) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRBase58Decode() test 3\n", __func__); s = "1111111111111111111111111111111111111111111111111111111111111111111"; @@ -240,7 +249,7 @@ int BRBase58Tests() char str4[BRBase58Encode(NULL, 0, buf4, len4)]; BRBase58Encode(str4, sizeof(str4), buf4, len4); - if (strcmp(str4, s) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: Base58Decode() test 4\n", __func__); + if (strcmp(str4, s) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRBase58Decode() test 4\n", __func__); s = "111111111111111111111111111111111111111111111111111111111111111111z"; @@ -249,7 +258,7 @@ int BRBase58Tests() char str5[BRBase58Encode(NULL, 0, buf5, len5)]; BRBase58Encode(str5, sizeof(str5), buf5, len5); - if (strcmp(str5, s) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: Base58Decode() test 5\n", __func__); + if (strcmp(str5, s) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRBase58Decode() test 5\n", __func__); s = "z"; @@ -258,7 +267,7 @@ int BRBase58Tests() char str6[BRBase58Encode(NULL, 0, buf6, len6)]; BRBase58Encode(str6, sizeof(str6), buf6, len6); - if (strcmp(str6, s) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: Base58Decode() test 6\n", __func__); + if (strcmp(str6, s) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRBase58Decode() test 6\n", __func__); s = NULL; @@ -311,6 +320,40 @@ int BRBase58Tests() return r; } +int BRBech32Tests() +{ + int r = 1; + uint8_t b[52]; + char h[84]; + char *s, addr[91]; + size_t l; + + s = "\x00\x14\x75\x1e\x76\xe8\x19\x91\x96\xd4\x54\x94\x1c\x45\xd1\xb3\xa3\x23\xf1\x43\x3b\xd6"; + l = BRBech32Decode(h, b, "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4"); + if (l != 22 || strcmp(h, "bc") || memcmp(s, b, l)) + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRBech32Decode() test 1", __func__); + + l = BRBech32Decode(h, b, "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"); + if (l != 22 || strcmp(h, "bc") || memcmp(s, b, l)) + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRBech32Decode() test 2", __func__); + + l = BRBech32Encode(addr, "bc", b); + if (l == 0 || strcmp(addr, "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")) + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRBech32Encode() test 2", __func__); + + s = "\x52\x10\x75\x1e\x76\xe8\x19\x91\x96\xd4\x54\x94\x1c\x45\xd1\xb3\xa3\x23"; + l = BRBech32Decode(h, b, "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj"); + if (l != 18 || strcmp(h, "bc") || memcmp(s, b, l)) + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRBech32Decode() test 3", __func__); + + l = BRBech32Encode(addr, "bc", b); + if (l == 0 || strcmp(addr, "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj")) + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRBech32Encode() test 3", __func__); + + if (! r) fprintf(stderr, "\n "); + return r; +} + int BRHashTests() { // test sha1 @@ -1068,7 +1111,7 @@ int BRKeyTests() #endif // signing - BRKeySetSecret(&key, &u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"), 1); + BRKeySetSecret(&key, &uint256("0000000000000000000000000000000000000000000000000000000000000001"), 1); msg = "Everything should be made as simple as possible, but not simpler."; BRSHA256(&md, msg, strlen(msg)); sigLen = BRKeySign(&key, sig, sizeof(sig), md); @@ -1083,7 +1126,7 @@ int BRKeyTests() if (! BRKeyVerify(&key, md, sig, sigLen)) r = 0, fprintf(stderr, "***FAILED*** %s: BRKeyVerify() test 1\n", __func__); - BRKeySetSecret(&key, &u256_hex_decode("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"), 1); + BRKeySetSecret(&key, &uint256("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"), 1); msg = "Equations are more important to me, because politics is for the present, but an equation is something for " "eternity."; BRSHA256(&md, msg, strlen(msg)); @@ -1099,7 +1142,7 @@ int BRKeyTests() if (! BRKeyVerify(&key, md, sig, sigLen)) r = 0, fprintf(stderr, "***FAILED*** %s: BRKeyVerify() test 2\n", __func__); - BRKeySetSecret(&key, &u256_hex_decode("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"), 1); + BRKeySetSecret(&key, &uint256("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"), 1); msg = "Not only is the Universe stranger than we think, it is stranger than we can think."; BRSHA256(&md, msg, strlen(msg)); sigLen = BRKeySign(&key, sig, sizeof(sig), md); @@ -1114,7 +1157,7 @@ int BRKeyTests() if (! BRKeyVerify(&key, md, sig, sigLen)) r = 0, fprintf(stderr, "***FAILED*** %s: BRKeyVerify() test 3\n", __func__); - BRKeySetSecret(&key, &u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"), 1); + BRKeySetSecret(&key, &uint256("0000000000000000000000000000000000000000000000000000000000000001"), 1); msg = "How wonderful that we have met with a paradox. Now we have some hope of making progress."; BRSHA256(&md, msg, strlen(msg)); sigLen = BRKeySign(&key, sig, sizeof(sig), md); @@ -1129,7 +1172,7 @@ int BRKeyTests() if (! BRKeyVerify(&key, md, sig, sigLen)) r = 0, fprintf(stderr, "***FAILED*** %s: BRKeyVerify() test 4\n", __func__); - BRKeySetSecret(&key, &u256_hex_decode("69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64"), 1); + BRKeySetSecret(&key, &uint256("69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64"), 1); msg = "Computer science is no more about computers than astronomy is about telescopes."; BRSHA256(&md, msg, strlen(msg)); sigLen = BRKeySign(&key, sig, sizeof(sig), md); @@ -1144,7 +1187,7 @@ int BRKeyTests() if (! BRKeyVerify(&key, md, sig, sigLen)) r = 0, fprintf(stderr, "***FAILED*** %s: BRKeyVerify() test 5\n", __func__); - BRKeySetSecret(&key, &u256_hex_decode("00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637"), 1); + BRKeySetSecret(&key, &uint256("00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637"), 1); msg = "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not" " learning anywhere near enough"; BRSHA256(&md, msg, strlen(msg)); @@ -1160,7 +1203,7 @@ int BRKeyTests() if (! BRKeyVerify(&key, md, sig, sigLen)) r = 0, fprintf(stderr, "***FAILED*** %s: BRKeyVerify() test 6\n", __func__); - BRKeySetSecret(&key, &u256_hex_decode("000000000000000000000000000000000000000000056916d0f9b31dc9b637f3"), 1); + BRKeySetSecret(&key, &uint256("000000000000000000000000000000000000000000056916d0f9b31dc9b637f3"), 1); msg = "The question of whether computers can think is like the question of whether submarines can swim."; BRSHA256(&md, msg, strlen(msg)); sigLen = BRKeySign(&key, sig, sizeof(sig), md); @@ -1176,7 +1219,7 @@ int BRKeyTests() r = 0, fprintf(stderr, "***FAILED*** %s: BRKeyVerify() test 7\n", __func__); // compact signing - BRKeySetSecret(&key, &u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"), 1); + BRKeySetSecret(&key, &uint256("0000000000000000000000000000000000000000000000000000000000000001"), 1); msg = "foo"; BRSHA256(&md, msg, strlen(msg)); sigLen = BRKeyCompactSign(&key, sig, sizeof(sig), md); @@ -1189,7 +1232,7 @@ int BRKeyTests() if (pkLen1 != pkLen || memcmp(pubKey, pubKey1, pkLen) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRKeyCompactSign() test 1\n", __func__); - BRKeySetSecret(&key, &u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"), 0); + BRKeySetSecret(&key, &uint256("0000000000000000000000000000000000000000000000000000000000000001"), 0); msg = "foo"; BRSHA256(&md, msg, strlen(msg)); sigLen = BRKeyCompactSign(&key, sig, sizeof(sig), md); @@ -1354,23 +1397,35 @@ int BRBIP38KeyTests() int BRAddressTests() { int r = 1; - UInt256 secret = u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"); + UInt256 secret = uint256("0000000000000000000000000000000000000000000000000000000000000001"); BRKey k; BRAddress addr, addr2; BRKeySetSecret(&k, &secret, 1); if (! BRKeyAddress(&k, addr.s, sizeof(addr))) - r = 0, fprintf(stderr, "***FAILED*** %s: BRKeyAddress()\n", __func__); + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRKeyAddress()", __func__); uint8_t script[BRAddressScriptPubKey(NULL, 0, addr.s)]; size_t scriptLen = BRAddressScriptPubKey(script, sizeof(script), addr.s); BRAddressFromScriptPubKey(addr2.s, sizeof(addr2), script, scriptLen); if (! BRAddressEq(&addr, &addr2)) - r = 0, fprintf(stderr, "***FAILED*** %s: BRAddressFromScriptPubKey()\n", __func__); + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRAddressFromScriptPubKey() test 1", __func__); // TODO: test BRAddressFromScriptSig() + BRAddress addr3; + char script2[] = "\0\x14\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + if (! BRAddressFromScriptPubKey(addr3.s, sizeof(addr3), (uint8_t *)script2, sizeof(script2))) + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRAddressFromScriptPubKey() test 2", __func__); + + uint8_t script3[BRAddressScriptPubKey(NULL, 0, addr3.s)]; + size_t script3Len = BRAddressScriptPubKey(script3, sizeof(script3), addr3.s); + + if (script3Len != sizeof(script2) || memcmp(script2, script3, sizeof(script2))) + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRAddressScriptPubKey() test", __func__); + + if (! r) fprintf(stderr, "\n "); return r; } @@ -1530,36 +1585,34 @@ int BRBIP32SequenceTests() printf("\n"); BRBIP32PrivKey(&key, &seed, sizeof(seed), SEQUENCE_INTERNAL_CHAIN, 2 | 0x80000000); - printf("000102030405060708090a0b0c0d0e0f/0H/1/2H prv = %s\n", u256_hex_encode(key.secret)); - if (! UInt256Eq(key.secret, u256_hex_decode("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"))) + printf("000102030405060708090a0b0c0d0e0f/0H/1/2H prv = %s\n", u256hex(key.secret)); + if (! UInt256Eq(key.secret, uint256("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"))) r = 0, fprintf(stderr, "***FAILED*** %s: BRBIP32PrivKey() test 1\n", __func__); // test for correct zero padding of private keys BRBIP32PrivKey(&key, &seed, sizeof(seed), SEQUENCE_EXTERNAL_CHAIN, 97); - printf("000102030405060708090a0b0c0d0e0f/0H/0/97 prv = %s\n", u256_hex_encode(key.secret)); - if (! UInt256Eq(key.secret, u256_hex_decode("00136c1ad038f9a00871895322a487ed14f1cdc4d22ad351cfa1a0d235975dd7"))) + printf("000102030405060708090a0b0c0d0e0f/0H/0/97 prv = %s\n", u256hex(key.secret)); + if (! UInt256Eq(key.secret, uint256("00136c1ad038f9a00871895322a487ed14f1cdc4d22ad351cfa1a0d235975dd7"))) r = 0, fprintf(stderr, "***FAILED*** %s: BRBIP32PrivKey() test 2\n", __func__); BRMasterPubKey mpk = BRBIP32MasterPubKey(&seed, sizeof(seed)); // printf("000102030405060708090a0b0c0d0e0f/0H fp:%08x chain:%s pubkey:%02x%s\n", be32(mpk.fingerPrint), -// u256_hex_encode(mpk.chainCode), mpk.pubKey[0], u256_hex_encode(*(UInt256 *)&mpk.pubKey[1])); +// u256hex(mpk.chainCode), mpk.pubKey[0], u256hex(*(UInt256 *)&mpk.pubKey[1])); // if (be32(mpk.fingerPrint) != 0x3442193e || -// ! UInt256Eq(mpk.chainCode, -// u256_hex_decode("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141")) || +// ! UInt256Eq(mpk.chainCode, uint256("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141")) || // mpk.pubKey[0] != 0x03 || // ! UInt256Eq(*(UInt256 *)&mpk.pubKey[1], -// u256_hex_decode("5a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"))) +// uint256("5a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"))) // r = 0, fprintf(stderr, "***FAILED*** %s: BRBIP32MasterPubKey() test\n", __func__); uint8_t pubKey[33]; BRBIP32PubKey(pubKey, sizeof(pubKey), mpk, SEQUENCE_EXTERNAL_CHAIN, 0); - printf("000102030405060708090a0b0c0d0e0f/0H/0/0 pub = %02x%s\n", pubKey[0], - u256_hex_encode(*(UInt256 *)&pubKey[1])); + printf("000102030405060708090a0b0c0d0e0f/0H/0/0 pub = %02x%s\n", pubKey[0], u256hex(*(UInt256 *)&pubKey[1])); if (pubKey[0] != 0x02 || ! UInt256Eq(*(UInt256 *)&pubKey[1], - u256_hex_decode("7b6a7dd645507d775215a9035be06700e1ed8c541da9351b4bd14bd50ab61428"))) + uint256("7b6a7dd645507d775215a9035be06700e1ed8c541da9351b4bd14bd50ab61428"))) r = 0, fprintf(stderr, "***FAILED*** %s: BRBIP32PubKey() test\n", __func__); UInt512 dk; @@ -1569,8 +1622,13 @@ int BRBIP32SequenceTests() "banner amused fringe fox insect roast aunt prefer hollow basic ladder", NULL); BRBIP32BitIDKey(&key, dk.u8, sizeof(dk), 0, "http://bitid.bitcoin.blue/callback"); BRKeyAddress(&key, addr.s, sizeof(addr)); +#if LITECOIN_TESTNET + if (strncmp(addr.s, "mxZ2Dn9vcyNeKh9DNHZw6d6NrxeYCVNjc2", sizeof(addr)) != 0) + r = 0, fprintf(stderr, "***FAILED*** %s: BRBIP32BitIDKey() test\n", __func__); +#else if (strncmp(addr.s, "1J34vj4wowwPYafbeibZGht3zy3qERoUM1", sizeof(addr)) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRBIP32BitIDKey() test\n", __func__); +#endif // TODO: XXX test BRBIP32SerializeMasterPrivKey() // TODO: XXX test BRBIP32SerializeMasterPubKey() @@ -1579,11 +1637,57 @@ int BRBIP32SequenceTests() return r; } +static int BRTxOutputEqual(BRTxOutput *out1, BRTxOutput *out2) { + return out1->amount == out2->amount + && 0 == memcmp (out1->address, out2->address, sizeof (out1->address)) + && out1->scriptLen == out2->scriptLen + && 0 == memcmp (out1->script, out2->script, out1->scriptLen * sizeof (uint8_t)); +} + + +// +static int BRTxInputEqual(BRTxInput *in1, BRTxInput *in2) { + return 0 == memcmp(&in1->txHash, &in2->txHash, sizeof(UInt256)) + && in1->index == in2->index + && 0 == memcmp(in1->address, in2->address, sizeof(in1->address)) + && in1->amount == in2->amount + && in1->scriptLen == in2->scriptLen + && 0 == memcmp(in1->script, in2->script, in1->scriptLen * sizeof(uint8_t)) + && in1->sigLen == in2->sigLen + && 0 == memcmp(in1->signature, in2->signature, in1->sigLen * sizeof(uint8_t)) + && in1->sequence == in2->sequence; +} + +// true if tx1 and tx2 have equal data (in their respective structures). +static int BRTransactionEqual (BRTransaction *tx1, BRTransaction *tx2) { + if (memcmp (&tx1->txHash, &tx2->txHash, sizeof(UInt256)) + || tx1->version != tx2->version + || tx1->lockTime != tx2->lockTime + || tx1->blockHeight != tx2->blockHeight + || tx1->timestamp != tx2->timestamp + || array_count(tx1->inputs) != array_count(tx2->inputs) + || array_count(tx1->outputs) != array_count(tx2->outputs)) + return 0; + + // Inputs + if (NULL != tx1->inputs) + for (int i = 0; i < array_count(tx1->inputs); i++) + if (!BRTxInputEqual(&tx1->inputs[i], &tx2->inputs[i])) + return 0; + // Outputs + if (NULL != tx1->outputs) + for (int i = 0; i < array_count(tx1->outputs); i++) + if (!BRTxOutputEqual(&tx1->outputs[i], &tx2->outputs[i])) + return 0; + + return 1; +} + int BRTransactionTests() { int r = 1; - UInt256 secret = u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"), - inHash = u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"); + UInt256 secret = uint256("0000000000000000000000000000000000000000000000000000000000000001"), + inHash = uint256("0000000000000000000000000000000000000000000000000000000000000001"); BRKey k[2]; BRAddress address, addr; @@ -1602,18 +1706,18 @@ int BRTransactionTests() uint8_t buf[BRTransactionSerialize(tx, NULL, 0)]; // test serializing/parsing unsigned tx size_t len = BRTransactionSerialize(tx, buf, sizeof(buf)); - if (len == 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRTransactionSerialize() test 0\n", __func__); + if (len == 0) r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionSerialize() test 0", __func__); BRTransactionFree(tx); tx = BRTransactionParse(buf, len); if (! tx || tx->inCount != 1 || tx->outCount != 2) - r = 0, fprintf(stderr, "***FAILED*** %s: BRTransactionParse() test 0\n", __func__); + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionParse() test 0", __func__); if (! tx) return r; BRTransactionSign(tx, 0, k, 2); BRAddressFromScriptSig(addr.s, sizeof(addr), tx->inputs[0].signature, tx->inputs[0].sigLen); if (! BRTransactionIsSigned(tx) || ! BRAddressEq(&address, &addr)) - r = 0, fprintf(stderr, "***FAILED*** %s: BRTransactionSign() test 1\n", __func__); + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionSign() test 1", __func__); uint8_t buf2[BRTransactionSerialize(tx, NULL, 0)]; size_t len2 = BRTransactionSerialize(tx, buf2, sizeof(buf2)); @@ -1622,14 +1726,14 @@ int BRTransactionTests() tx = BRTransactionParse(buf2, len2); if (! tx || ! BRTransactionIsSigned(tx)) - r = 0, fprintf(stderr, "***FAILED*** %s: BRTransactionParse() test 1\n", __func__); + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionParse() test 1", __func__); if (! tx) return r; uint8_t buf3[BRTransactionSerialize(tx, NULL, 0)]; size_t len3 = BRTransactionSerialize(tx, buf3, sizeof(buf3)); if (len2 != len3 || memcmp(buf2, buf3, len2) != 0) - r = 0, fprintf(stderr, "***FAILED*** %s: BRTransactionSerialize() test 1\n", __func__); + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionSerialize() test 1", __func__); BRTransactionFree(tx); tx = BRTransactionNew(); @@ -1657,7 +1761,7 @@ int BRTransactionTests() BRAddressFromScriptSig(addr.s, sizeof(addr), tx->inputs[tx->inCount - 1].signature, tx->inputs[tx->inCount - 1].sigLen); if (! BRTransactionIsSigned(tx) || ! BRAddressEq(&address, &addr)) - r = 0, fprintf(stderr, "***FAILED*** %s: BRTransactionSign() test 2\n", __func__); + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionSign() test 2", __func__); uint8_t buf4[BRTransactionSerialize(tx, NULL, 0)]; size_t len4 = BRTransactionSerialize(tx, buf4, sizeof(buf4)); @@ -1665,16 +1769,42 @@ int BRTransactionTests() BRTransactionFree(tx); tx = BRTransactionParse(buf4, len4); if (! tx || ! BRTransactionIsSigned(tx)) - r = 0, fprintf(stderr, "***FAILED*** %s: BRTransactionParse() test 2\n", __func__); + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionParse() test 2", __func__); if (! tx) return r; uint8_t buf5[BRTransactionSerialize(tx, NULL, 0)]; size_t len5 = BRTransactionSerialize(tx, buf5, sizeof(buf5)); if (len4 != len5 || memcmp(buf4, buf5, len4) != 0) - r = 0, fprintf(stderr, "***FAILED*** %s: BRTransactionSerialize() test 2\n", __func__); + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionSerialize() test 2", __func__); BRTransactionFree(tx); + BRTransaction *src = BRTransactionNew (); + BRTransactionAddInput(src, inHash, 0, 1, script, scriptLen, NULL, 0, TXIN_SEQUENCE); + BRTransactionAddInput(src, inHash, 0, 1, script, scriptLen, NULL, 0, TXIN_SEQUENCE); + BRTransactionAddOutput(src, 1000000, script, scriptLen); + BRTransactionAddOutput(src, 1000000, script, scriptLen); + BRTransactionAddOutput(src, 1000000, script, scriptLen); + + BRTransaction *tgt = BRTransactionCopy(src); + if (!BRTransactionEqual(tgt, src)) + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionCopy() test 1", __func__); + + tgt->blockHeight++; + if (BRTransactionEqual(tgt, src)) // fail if equal + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionCopy() test 2", __func__); + + BRTransactionFree(tgt); + BRTransactionFree(src); + + src = BRTransactionParse(buf4, len4); + tgt = BRTransactionCopy(src); + if (!BRTransactionEqual(tgt, src)) + r = 0, fprintf(stderr, "\n***FAILED*** %s: BRTransactionCopy() test 3", __func__); + BRTransactionFree(tgt); + BRTransactionFree(src); + + if (! r) fprintf(stderr, "\n "); return r; } @@ -1685,18 +1815,18 @@ static void walletBalanceChanged(void *info, uint64_t balance) static void walletTxAdded(void *info, BRTransaction *tx) { - printf("tx added: %s\n", u256_hex_encode(tx->txHash)); + printf("tx added: %s\n", u256hex(tx->txHash)); } static void walletTxUpdated(void *info, const UInt256 txHashes[], size_t txCount, uint32_t blockHeight, uint32_t timestamp) { - for (size_t i = 0; i < txCount; i++) printf("tx updated: %s\n", u256_hex_encode(txHashes[i])); + for (size_t i = 0; i < txCount; i++) printf("tx updated: %s\n", u256hex(txHashes[i])); } static void walletTxDeleted(void *info, UInt256 txHash, int notifyUser, int recommendRescan) { - printf("tx deleted: %s\n", u256_hex_encode(txHash)); + printf("tx deleted: %s\n", u256hex(txHash)); } // TODO: test standard free transaction no change @@ -1712,8 +1842,8 @@ int BRWalletTests() int r = 1; BRMasterPubKey mpk = BRBIP32MasterPubKey("", 1); BRWallet *w = BRWalletNew(NULL, 0, mpk); - UInt256 secret = u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"), - inHash = u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"); + UInt256 secret = uint256("0000000000000000000000000000000000000000000000000000000000000001"), + inHash = uint256("0000000000000000000000000000000000000000000000000000000000000001"); BRKey k; BRAddress addr, recvAddr = BRWalletReceiveAddress(w); BRTransaction *tx; @@ -1942,6 +2072,23 @@ int BRBloomFilterTests() return r; } +// true if block and otherBlock have equal data (in their respective structures). +static int BRMerkleBlockEqual (const BRMerkleBlock *block1, const BRMerkleBlock *block2) { + return 0 == memcmp(&block1->blockHash, &block2->blockHash, sizeof(UInt256)) + && block1->version == block2->version + && 0 == memcmp(&block1->prevBlock, &block2->prevBlock, sizeof(UInt256)) + && 0 == memcmp(&block1->merkleRoot, &block2->merkleRoot, sizeof(UInt256)) + && block1->timestamp == block2->timestamp + && block1->target == block2->target + && block1->nonce == block2->nonce + && block1->totalTx == block2->totalTx + && block1->hashesCount == block2->hashesCount + && 0 == memcmp(block1->hashes, block2->hashes, block1->hashesCount * sizeof(UInt256)) + && block1->flagsLen == block2->flagsLen + && 0 == memcmp(block1->flags, block2->flags, block1->flagsLen * sizeof(uint8_t)) + && block1->height == block2->height; +} + int BRMerkleBlockTests() { int r = 1; @@ -1965,7 +2112,7 @@ int BRMerkleBlockTests() b = BRMerkleBlockParse((uint8_t *)block, sizeof(block) - 1); if (! UInt256Eq(b->blockHash, - UInt256Reverse(u256_hex_decode("00000000000080b66c911bd5ba14a74260057311eaeb1982802f7010f1a9f090")))) + UInt256Reverse(uint256("00000000000080b66c911bd5ba14a74260057311eaeb1982802f7010f1a9f090")))) r = 0, fprintf(stderr, "***FAILED*** %s: BRMerkleBlockParse() test\n", __func__); if (! BRMerkleBlockIsValid(b, (uint32_t)time(NULL))) @@ -1975,8 +2122,7 @@ int BRMerkleBlockTests() memcmp(block, block2, sizeof(block2)) != 0) r = 0, fprintf(stderr, "***FAILED*** %s: BRMerkleBlockSerialize() test\n", __func__); - if (! BRMerkleBlockContainsTxHash(b, - u256_hex_decode("4c30b63cfcdc2d35e3329421b9805ef0c6565d35381ca857762ea0b3a5a128bb"))) + if (! BRMerkleBlockContainsTxHash(b, uint256("4c30b63cfcdc2d35e3329421b9805ef0c6565d35381ca857762ea0b3a5a128bb"))) r = 0, fprintf(stderr, "***FAILED*** %s: BRMerkleBlockContainsTxHash() test\n", __func__); if (BRMerkleBlockTxHashes(b, NULL, 0) != 4) @@ -1986,20 +2132,16 @@ int BRMerkleBlockTests() BRMerkleBlockTxHashes(b, txHashes, 4); - if (! UInt256Eq(txHashes[0], - u256_hex_decode("4c30b63cfcdc2d35e3329421b9805ef0c6565d35381ca857762ea0b3a5a128bb"))) + if (! UInt256Eq(txHashes[0], uint256("4c30b63cfcdc2d35e3329421b9805ef0c6565d35381ca857762ea0b3a5a128bb"))) r = 0, fprintf(stderr, "***FAILED*** %s: BRMerkleBlockTxHashes() test 1\n", __func__); - if (! UInt256Eq(txHashes[1], - u256_hex_decode("ca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb"))) + if (! UInt256Eq(txHashes[1], uint256("ca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb"))) r = 0, fprintf(stderr, "***FAILED*** %s: BRMerkleBlockTxHashes() test 2\n", __func__); - if (! UInt256Eq(txHashes[2], - u256_hex_decode("bb15ac1d57d0182aaee61c74743a9c4f785895e563909bafec45c9a2b0ff3181"))) + if (! UInt256Eq(txHashes[2], uint256("bb15ac1d57d0182aaee61c74743a9c4f785895e563909bafec45c9a2b0ff3181"))) r = 0, fprintf(stderr, "***FAILED*** %s: BRMerkleBlockTxHashes() test 3\n", __func__); - if (! UInt256Eq(txHashes[3], - u256_hex_decode("c9ab658448c10b6921b7a4ce3021eb22ed6bb6a7fde1e5bcc4b1db6615c6abc5"))) + if (! UInt256Eq(txHashes[3], uint256("c9ab658448c10b6921b7a4ce3021eb22ed6bb6a7fde1e5bcc4b1db6615c6abc5"))) r = 0, fprintf(stderr, "***FAILED*** %s: BRMerkleBlockTxHashes() test 4\n", __func__); // TODO: test a block with an odd number of tree rows both at the tx level and merkle node level @@ -2008,6 +2150,18 @@ int BRMerkleBlockTests() // TODO: test (CVE-2012-2459) vulnerability + BRMerkleBlock *c = BRMerkleBlockCopy(b); + + if (!BRMerkleBlockEqual(b, c)) + r = 0, fprintf(stderr, "***FAILED*** %s: BRMerkleBlockEqual() test 1\n", __func__); + + c->height++; + if (BRMerkleBlockEqual(b, c)) // fail if equal + r = 0, fprintf(stderr, "***FAILED*** %s: BRMerkleBlockEqual() test 2\n", __func__); + + if (c) BRMerkleBlockFree(c); + + if (b) BRMerkleBlockFree(b); return r; } @@ -2375,9 +2529,8 @@ int BRPaymentProtocolEncryptionTests() uint8_t id[32] = { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00 }; - BRKeySetSecret(&senderKey, &u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000001"), 1); - BRKeySetSecret(&receiverKey, &u256_hex_decode("0000000000000000000000000000000000000000000000000000000000000002"), - 1); + BRKeySetSecret(&senderKey, &uint256("0000000000000000000000000000000000000000000000000000000000000001"), 1); + BRKeySetSecret(&receiverKey, &uint256("0000000000000000000000000000000000000000000000000000000000000002"), 1); BRPaymentProtocolInvoiceRequest *req = BRPaymentProtocolInvoiceRequestNew(&senderKey, 0, NULL, NULL, 0, NULL, NULL, NULL, 0); @@ -2455,7 +2608,7 @@ void BRPeerAcceptMessageTest(BRPeer *peer, const uint8_t *msg, size_t len, const int BRPeerTests() { int r = 1; - BRPeer *p = BRPeerNew(); + BRPeer *p = BRPeerNew(BR_CHAIN_PARAMS.magicNumber); const char msg[] = "my message"; BRPeerAcceptMessageTest(p, (const uint8_t *)msg, sizeof(msg) - 1, "inv"); @@ -2474,6 +2627,8 @@ int BRRunTests() printf("%s\n", (BRSetTests()) ? "success" : (fail++, "***FAIL***")); printf("BRBase58Tests... "); printf("%s\n", (BRBase58Tests()) ? "success" : (fail++, "***FAIL***")); + printf("BRBech32Tests... "); + printf("%s\n", (BRBech32Tests()) ? "success" : (fail++, "***FAIL***")); printf("BRHashTests... "); printf("%s\n", (BRHashTests()) ? "success" : (fail++, "***FAIL***")); printf("BRMacTests... "); @@ -2552,7 +2707,7 @@ int main(int argc, const char *argv[]) // BRWalletSetCallbacks(wallet, wallet, walletBalanceChanged, walletTxAdded, walletTxUpdated, walletTxDeleted); // printf("wallet created with first receive address: %s\n", BRWalletReceiveAddress(wallet).s); // -// manager = BRPeerManagerNew(wallet, BIP39_CREATION_TIME, NULL, 0, NULL, 0); +// manager = BRPeerManagerNew(&BRMainNetParams, wallet, BIP39_CREATION_TIME, NULL, 0, NULL, 0); // BRPeerManagerSetCallbacks(manager, manager, syncStarted, syncStopped, txStatusUpdate, NULL, NULL, NULL, NULL); // // BRPeerManagerConnect(manager); From 175443e05e4983993119ca2576765d98c4b66cab Mon Sep 17 00:00:00 2001 From: Mohamed Barry Date: Wed, 15 Apr 2020 21:22:00 +0100 Subject: [PATCH 2/3] add missing files --- BRBech32.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ BRBech32.h | 48 ++++++++++++++++ BRChainParams.h | 136 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 328 insertions(+) create mode 100644 BRBech32.c create mode 100644 BRBech32.h create mode 100644 BRChainParams.h diff --git a/BRBech32.c b/BRBech32.c new file mode 100644 index 000000000..7773895c5 --- /dev/null +++ b/BRBech32.c @@ -0,0 +1,144 @@ +// +// BRBech32.c +// +// Created by Aaron Voisine on 1/20/18. +// Copyright (c) 2018 breadwallet LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "BRBech32.h" +#include "BRAddress.h" +#include "BRCrypto.h" +#include +#include +#include +#include +#include + +// bech32 address format: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki + +#define polymod(x) ((((x) & 0x1ffffff) << 5) ^ (-(((x) >> 25) & 1) & 0x3b6a57b2) ^\ + (-(((x) >> 26) & 1) & 0x26508e6d) ^ (-(((x) >> 27) & 1) & 0x1ea119fa) ^\ + (-(((x) >> 28) & 1) & 0x3d4233dd) ^ (-(((x) >> 29) & 1) & 0x2a1462b3)) + +// returns the number of bytes written to data42 (maximum of 42) +size_t BRBech32Decode(char *hrp84, uint8_t *data42, const char *addr) +{ + size_t i, j, bufLen, addrLen, sep; + uint32_t x, chk = 1; + uint8_t c, ver = 0xff, buf[52], upper = 0, lower = 0; + + assert(hrp84 != NULL); + assert(data42 != NULL); + assert(addr != NULL); + + for (i = 0; addr && addr[i]; i++) { + if (addr[i] < 33 || addr[i] > 126) return 0; + if (islower(addr[i])) lower = 1; + if (isupper(addr[i])) upper = 1; + } + + addrLen = sep = i; + while (sep > 0 && addr[sep] != '1') sep--; + if (addrLen < 8 || addrLen > 90 || sep < 1 || sep + 2 + 6 > addrLen || (upper && lower)) return 0; + for (i = 0; i < sep; i++) chk = polymod(chk) ^ (tolower(addr[i]) >> 5); + chk = polymod(chk); + for (i = 0; i < sep; i++) chk = polymod(chk) ^ (addr[i] & 0x1f); + memset(buf, 0, sizeof(buf)); + + for (i = sep + 1, j = -1; i < addrLen; i++, j++) { + switch (tolower(addr[i])) { + case 'q': c = 0; break; case 'p': c = 1; break; case 'z': c = 2; break; case 'r': c = 3; break; + case 'y': c = 4; break; case '9': c = 5; break; case 'x': c = 6; break; case '8': c = 7; break; + case 'g': c = 8; break; case 'f': c = 9; break; case '2': c = 10; break; case 't': c = 11; break; + case 'v': c = 12; break; case 'd': c = 13; break; case 'w': c = 14; break; case '0': c = 15; break; + case 's': c = 16; break; case '3': c = 17; break; case 'j': c = 18; break; case 'n': c = 19; break; + case '5': c = 20; break; case '4': c = 21; break; case 'k': c = 22; break; case 'h': c = 23; break; + case 'c': c = 24; break; case 'e': c = 25; break; case '6': c = 26; break; case 'm': c = 27; break; + case 'u': c = 28; break; case 'a': c = 29; break; case '7': c = 30; break; case 'l': c = 31; break; + default: return 0; // invalid bech32 digit + } + + chk = polymod(chk) ^ c; + if (j == -1) ver = c; + if (j == -1 || i + 6 >= addrLen) continue; + x = (j % 8)*5 - ((j % 8)*5/8)*8; + buf[(j/8)*5 + (j % 8)*5/8] |= (c << 3) >> x; + if (x > 3) buf[(j/8)*5 + (j % 8)*5/8 + 1] |= c << (11 - x); + } + + bufLen = (addrLen - (sep + 2 + 6))*5/8; + if (hrp84 == NULL || data42 == NULL || chk != 1 || ver > 16 || bufLen < 2 || bufLen > 40) return 0; + assert(sep < 84); + for (i = 0; i < sep; i++) hrp84[i] = tolower(addr[i]); + hrp84[sep] = '\0'; + data42[0] = (ver == 0) ? OP_0 : ver + OP_1 - 1; + data42[1] = bufLen; + assert(bufLen <= 40); + memcpy(&data42[2], buf, bufLen); + return 2 + bufLen; +} + +// data must contain a valid BIP141 witness program +// returns the number of bytes written to addr91 (maximum of 91) +size_t BRBech32Encode(char *addr91, const char *hrp, const uint8_t data[]) +{ + static const char chars[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + char addr[91]; + uint32_t x, chk = 1; + uint8_t ver, a, b = 0, c = 0; + size_t i, j, len; + + assert(addr91 != NULL); + assert(hrp != NULL); + assert(data != NULL); + + for (i = 0; hrp && hrp[i]; i++) { + if (i > 83 || hrp[i] < 33 || hrp[i] > 126 || isupper(hrp[i])) return 0; + chk = polymod(chk) ^ (hrp[i] >> 5); + addr[i] = hrp[i]; + } + + chk = polymod(chk); + for (j = 0; j < i; j++) chk = polymod(chk) ^ (hrp[j] & 0x1f); + addr[i++] = '1'; + if (i < 1 || data == NULL || (data[0] > OP_0 && data[0] < OP_1)) return 0; + ver = (data[0] >= OP_1) ? data[0] + 1 - OP_1 : 0; + len = data[1]; + if (ver > 16 || len < 2 || len > 40 || i + 1 + len + 6 >= 91) return 0; + chk = polymod(chk) ^ ver; + addr[i++] = chars[ver]; + + for (j = 0; j <= len; j++) { + a = b, b = (j < len) ? data[2 + j] : 0; + x = (j % 5)*8 - ((j % 5)*8/5)*5; + c = ((a << (5 - x)) | (b >> (3 + x))) & 0x1f; + if (j < len || j % 5 > 0) chk = polymod(chk) ^ c, addr[i++] = chars[c]; + if (x >= 2) c = (b >> (x - 2)) & 0x1f; + if (x >= 2 && j < len) chk = polymod(chk) ^ c, addr[i++] = chars[c]; + } + + for (j = 0; j < 6; j++) chk = polymod(chk); + chk ^= 1; + for (j = 0; j < 6; ++j) addr[i++] = chars[(chk >> ((5 - j)*5)) & 0x1f]; + addr[i++] = '\0'; + memcpy(addr91, addr, i); + return i; +} + diff --git a/BRBech32.h b/BRBech32.h new file mode 100644 index 000000000..e9b9ca445 --- /dev/null +++ b/BRBech32.h @@ -0,0 +1,48 @@ +// +// BRBech32.h +// +// Created by Aaron Voisine on 1/20/18. +// Copyright (c) 2018 breadwallet LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef BRBech32_h +#define BRBech32_h + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// bech32 address format: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki + +// returns the number of bytes written to data42 (maximum of 42) +size_t BRBech32Decode(char *hrp84, uint8_t *data42, const char *addr); + +// data must contain a valid BIP141 witness program +// returns the number of bytes written to addr91 (maximum of 91) +size_t BRBech32Encode(char *addr91, const char *hrp, const uint8_t data[]); + +#ifdef __cplusplus +} +#endif + +#endif // BRBech32_h diff --git a/BRChainParams.h b/BRChainParams.h new file mode 100644 index 000000000..af16e6bc3 --- /dev/null +++ b/BRChainParams.h @@ -0,0 +1,136 @@ +// +// BRChainParams.h +// +// Created by Aaron Voisine on 1/10/18. +// Copyright (c) 2019 breadwallet LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef BRChainParams_h +#define BRChainParams_h + +#include "BRMerkleBlock.h" +#include "BRSet.h" +#include + +typedef struct { + uint32_t height; + UInt256 hash; + uint32_t timestamp; + uint32_t target; +} BRCheckPoint; + +typedef struct { + const char * const *dnsSeeds; // NULL terminated array of dns seeds + uint16_t standardPort; + uint32_t magicNumber; + uint64_t services; + int (*verifyDifficulty)(const BRMerkleBlock *block, const BRSet *blockSet); // blockSet must have last 2016 blocks + const BRCheckPoint *checkpoints; + size_t checkpointsCount; +} BRChainParams; + +static const char *BRMainNetDNSSeeds[] = { + "dnsseed.litecoinpool.org.", "seed-a.litecoin.loshan.co.uk.", "dnsseed.thrasher.io.", + "dnsseed.koin-project.com.", "dnsseed.litecointools.com.", NULL}; + +static const char *BRTestNetDNSSeeds[] = { + "testnet-seed.ltc.xurious.com.", "seed-b.litecoin.loshan.co.uk.", "dnsseed-testnet.thrasher.io.", NULL +}; + +// blockchain checkpoints - these are also used as starting points for partial chain downloads, so they must be at +// difficulty transition boundaries in order to verify the block difficulty at the immediately following transition +static const BRCheckPoint BRMainNetCheckpoints[] = { + { 0, uint256("12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2"), 1317972665, 0x1e0ffff0 }, + { 20160, uint256("633036c8df655531c2449b2d09b264cc0b49d945a89be23fd3c1a97361ca198c"), 1319798300, 0x1d055262 }, + { 40320, uint256("d148cdd2cf44069cef4b63f0feaf30a8d291ca9ea9ba7e83f226b9738c1d5e9c"), 1322522019, 0x1d018053 }, + { 60480, uint256("3250f0a560d55f039c34bfaee1b71297aa5104ac6641778f9a87d73232d12c6c"), 1325540574, 0x1d00e848 }, + { 80640, uint256("bedc0a090b740b1902d870aeb6caa89040a24e7d670d46f8ef035fd9d2e9ce80"), 1328779944, 0x1d00ab92 }, + { 100800, uint256("7b0b620d15f781faaaa73b43607a49d5becb2b803ef19b4010014646cc177a61"), 1331873688, 0x1d00ae9f }, + { 120960, uint256("dbd6249f30e5690890bc03dabcc0a526c46adcde572be06af4075b6ea28aa251"), 1334881566, 0x1d009e48 }, + { 141120, uint256("5d5e15a45cecf2b9528e36e63c407167423a2f9963a96bbce3b67b75fd10be2a"), 1338009318, 0x1d00d6a6 }, + { 161280, uint256("f595c754d0abcfe3616573bfabee01b230ec0ea6b2f2894c40214ea23d772b6c"), 1340918301, 0x1d008881 }, + { 181440, uint256("d7fa3152959f3c25e33edf825f7cbef75ee651d5f9183cc4ed8d19d57b8f35a4"), 1343534530, 0x1c1cd430 }, + { 201600, uint256("d481df8e8ce144fca9ae6b3157cc706e903c6ea161a13d2c421270354a02d6d0"), 1346567025, 0x1c1c89e8 }, + { 282240, uint256("8932095fba44bd6860fd71745c0dca908769221a47166ab1fb442b6cefcd53fb"), 1358801720, 0x1c0ced21 }, + { 342720, uint256("33f62e026a202be550e8a9df37d638d38991553544e279cb264123378bf46042"), 1367113967, 0x1c0095a5 }, + { 383040, uint256("5c0a443361c1356796a7db472c69433b6ce6108d61e4403fd9a9d91e01009ce3"), 1372971948, 0x1b481262 }, + { 443520, uint256("37d668803ed1efc24ffab4a2a90da9ac92679acf68370d7570f042c2bd6d651b"), 1382034998, 0x1b3f864f }, + { 504000, uint256("97db0624d3d5137bc085f0d731607314972bb4124b85b73420ef9aa5fc10d640"), 1390892377, 0x1b1aa868 }, + { 564480, uint256("c876276bf12754c2b265787d9e7ab83d429e59761dc63057f728529018db7834"), 1399724592, 0x1b099dce }, + { 624960, uint256("ccac71fafe98107b81ac3e0eed41190e4d47600962c93c49db8843b53f760bda"), 1408389228, 0x1b02552d }, + { 685440, uint256("29d2328990dda4c4870846d4e3d573785452bed68e6013930a83fc8d5fe89b09"), 1417289378, 0x1b01473b }, + { 745920, uint256("04809a35ff6e5054e21d14582072605b812b7d4ae11d3450e7c03a7237e1d35d"), 1426441593, 0x1b019b8c }, + { 806400, uint256("e2363e8b3e8f237b9b1bfc1c72ede80fef2c7bd1aabcd78afed82065a194b960"), 1435516150, 0x1b019268 }, + { 846720, uint256("6f5d94d7cfd01f1dbf4aa631b987f8e2ec9d0c57720604787b816bafe34192a8"), 1441561050, 0x1b0187a3 }, + { 901152, uint256("cfccdf8e3830ae4879e910051ac3dc583b4fb45b83be3a38019e5d9326dfa223"), 1449698771, 0x1b015b0e }, + { 953568, uint256("e46e01cf1239cffa69408ac162d517bac5a4899972e0328fd0ba4d93e8ad3764"), 1457542869, 0x1b013c91 }, + { 1058400, uint256("76ce37c66d449a4ffbfc35674cf932da701066a001dc223754f9250dd2bdbc62"), 1473296285, 0x1b013ca7 }, + { 1260000, uint256("85a22b528d805bf7a641d1d7c6d96ef5054beda3dcab6be7b83f2e3df24b33a8"), 1502976600, 0x1a25a0d3 }, + { 1411200, uint256("92c85b76f3d4bffca76b23717e4eb1b667c77c96fd52d4dd5dd843bbee64cd73"), 1524838967, 0x1a0203a7 } +}; + +static const BRCheckPoint BRTestNetCheckpoints[] = { + { 0, uint256("4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0"), 1486949366, 0x1e0ffff0 } +}; + +static int BRMainNetVerifyDifficulty(const BRMerkleBlock *block, const BRSet *blockSet) +{ + // const BRMerkleBlock *previous, *b = NULL; + // uint32_t i; + + // assert(block != NULL); + // assert(blockSet != NULL); + + // // check if we hit a difficulty transition, and find previous transition block + // if ((block->height % BLOCK_DIFFICULTY_INTERVAL) == 0) { + // for (i = 0, b = block; b && i < BLOCK_DIFFICULTY_INTERVAL; i++) { + // b = BRSetGet(blockSet, &b->prevBlock); + // } + // } + + // previous = BRSetGet(blockSet, &block->prevBlock); + // return BRMerkleBlockVerifyDifficulty(block, previous, (b) ? b->timestamp : 0); + return 1; +} + +static int BRTestNetVerifyDifficulty(const BRMerkleBlock *block, const BRSet *blockSet) +{ + return 1; // XXX skip testnet difficulty check for now +} + +static const BRChainParams BRMainNetParams = { + BRMainNetDNSSeeds, + 9333, // standardPort + 0xdbb6c0fb, // magicNumber + 0, // services + BRMainNetVerifyDifficulty, + BRMainNetCheckpoints, + sizeof(BRMainNetCheckpoints) / sizeof(*BRMainNetCheckpoints)}; + +static const BRChainParams BRTestNetParams = { + BRTestNetDNSSeeds, + 19335, // standardPort + 0xf1c8d2fd, // magicNumber + 0, // services + BRTestNetVerifyDifficulty, + BRTestNetCheckpoints, + sizeof(BRTestNetCheckpoints) / sizeof(*BRTestNetCheckpoints)}; + +#endif // BRChainParams_h From 0bb8fa52736e0022d2de2a884733fdb72fbac799 Mon Sep 17 00:00:00 2001 From: Mohamed Barry Date: Thu, 16 Apr 2020 20:32:50 +0100 Subject: [PATCH 3/3] add BRPeerManagerStandardPort method which returns the standard port used for chain params --- BRPeerManager.c | 9 +++++++++ BRPeerManager.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/BRPeerManager.c b/BRPeerManager.c index c1502ab89..62dbb26e3 100644 --- a/BRPeerManager.c +++ b/BRPeerManager.c @@ -1632,6 +1632,15 @@ void BRPeerManagerSetFixedPeer(BRPeerManager *manager, UInt128 address, uint16_t pthread_mutex_unlock(&manager->lock); } +uint16_t BRPeerManagerStandardPort(BRPeerManager *manager) +{ + assert(manager != NULL); + pthread_mutex_lock(&manager->lock); + uint16_t port = manager->params->standardPort; + pthread_mutex_unlock(&manager->lock); + return port; +} + // current connect status BRPeerStatus BRPeerManagerConnectStatus(BRPeerManager *manager) { diff --git a/BRPeerManager.h b/BRPeerManager.h index f01aa0af5..55c097e45 100644 --- a/BRPeerManager.h +++ b/BRPeerManager.h @@ -72,6 +72,9 @@ void BRPeerManagerSetFixedPeer(BRPeerManager *manager, UInt128 address, uint16_t // current connect status BRPeerStatus BRPeerManagerConnectStatus(BRPeerManager *manager); +// returns the standard port used for BRChainParams +uint16_t BRPeerManagerStandardPort(BRPeerManager *manager); + // connect to bitcoin peer-to-peer network (also call this whenever networkIsReachable() status changes) void BRPeerManagerConnect(BRPeerManager *manager);