CBByteArray * CBVersionChecksumBytesGetString(CBVersionChecksumBytes * self) { if (self->cachedString) { // Return cached string CBRetainObject(self->cachedString); return self->cachedString; } else { // Make string CBByteArrayReverseBytes(CBGetByteArray(self)); // Make this into little-endian CBBigInt bytes; CBBigIntAlloc(&bytes, CBGetByteArray(self)->length); bytes.length = CBGetByteArray(self)->length; memcpy(bytes.data, CBByteArrayGetData(CBGetByteArray(self)), bytes.length); char * string = CBEncodeBase58(&bytes); if (NOT string) return NULL; CBByteArray * str = CBNewByteArrayFromString(string, true, CBGetByteArray(self)->logError); if (NOT str) { free(string); return NULL; } CBByteArrayReverseBytes(CBGetByteArray(self)); // Now the string is got, back to big-endian. if (self->cacheString) { self->cachedString = str; CBRetainObject(str); // Retain for this object. } return str; // No additional retain. Retained from constructor. } }
void CBInitAlert(CBAlert * self, int32_t version, int64_t relayUntil, int64_t expiration, int32_t ID, int32_t cancel, int32_t minVer, int32_t maxVer, int32_t priority, CBByteArray * hiddenComment, CBByteArray * displayedComment, CBByteArray * reserved) { self->version = version; self->relayUntil = relayUntil; self->expiration = expiration; self->ID = ID; self->cancel = cancel; self->minVer = minVer; self->maxVer = maxVer; self->priority = priority; self->hiddenComment = hiddenComment; if (hiddenComment) CBRetainObject(hiddenComment); self->displayedComment = displayedComment; if (displayedComment) CBRetainObject(displayedComment); self->reserved = reserved; if (reserved) CBRetainObject(reserved); self->signature = NULL; self->payload = NULL; CBInitMessageByObject(CBGetMessage(self)); }
void CBNodeSendMessageOnNetworkThread(CBNetworkCommunicator * self, CBPeer * peer, CBMessage * message, void (*callback)(void *, void *)){ CBSendMessageData * data = malloc(sizeof(*data)); *data = (CBSendMessageData){self,peer,message,callback}; CBRetainObject(message); CBRetainObject(peer); // Shouldn't block in the cases where this thread already has a mutex used by the CBNetworkCommunicator code. CBRunOnEventLoop(self->eventLoop, CBNodeSendMessageOnNetworkThreadVoid, data, false); }
bool CBInitTransactionInput(CBTransactionInput * self,CBScript * script,uint32_t sequence,CBByteArray * prevOutHash,uint32_t prevOutIndex,void (*onErrorReceived)(CBError error,char *,...)){ if (script){ self->scriptObject = script; CBRetainObject(script); }else self->scriptObject = NULL; self->prevOut.hash = prevOutHash; CBRetainObject(prevOutHash); self->prevOut.index = prevOutIndex; self->sequence = sequence; if (NOT CBInitMessageByObject(CBGetMessage(self), onErrorReceived)) return false; return true; }
bool CBInitVersion(CBVersion * self,int32_t version,CBVersionServices services,int64_t time,CBNetworkAddress * addRecv,CBNetworkAddress * addSource,uint64_t nonce,CBByteArray * userAgent,int32_t blockHeight,void (*logError)(char *,...)){ self->version = version; self->services = services; self->time = time; self->addRecv = addRecv; CBRetainObject(addRecv); self->addSource = addSource; CBRetainObject(addSource); self->nonce = nonce; self->userAgent = userAgent; CBRetainObject(userAgent); self->blockHeight = blockHeight; if (NOT CBInitMessageByObject(CBGetMessage(self), logError)) return false; return true; }
bool CBInitNetworkAddress(CBNetworkAddress * self, uint64_t lastSeen, CBByteArray * ip, uint16_t port, CBVersionServices services, bool isPublic){ self->lastSeen = lastSeen; self->penalty = 0; self->ip = ip; self->isPublic = isPublic; if (NOT ip) { ip = CBNewByteArrayOfSize(16); if (NOT ip) return false; memset(CBByteArrayGetData(ip), 0, 16); self->type = CB_IP_INVALID; }else{ // Determine IP type self->type = CBGetIPType(CBByteArrayGetData(ip)); CBRetainObject(ip); } self->port = port; self->services = services; self->bucketSet = false; if (NOT CBInitMessageByObject(CBGetMessage(self))){ CBReleaseObject(ip); return false; } return true; }
bool CBInitInventoryItem(CBInventoryItem * self, CBInventoryItemType type, CBByteArray * hash){ self->type = type; self->hash = hash; CBRetainObject(hash); if (NOT CBInitMessageByObject(CBGetMessage(self))) return false; return true; }
bool CBInitInventoryItem(CBInventoryItem * self,CBInventoryItemType type,CBByteArray * hash,void (*logError)(char *,...)){ self->type = type; self->hash = hash; CBRetainObject(hash); if (NOT CBInitMessageByObject(CBGetMessage(self), logError)) return false; return true; }
CBByteArray * CBVersionChecksumBytesGetString(CBVersionChecksumBytes * self){ if (self->cachedString) { // Return cached string CBRetainObject(self->cachedString); return self->cachedString; }else{ // Make string CBByteArrayReverseBytes(CBGetByteArray(self)); // Make this into little-endian char * string = CBEncodeBase58(CBByteArrayGetData(CBGetByteArray(self)),CBGetByteArray(self)->length); CBByteArray * str = CBNewByteArrayWithData((uint8_t *)string, strlen(string), CBGetByteArray(self)->events); CBByteArrayReverseBytes(CBGetByteArray(self)); // Now the string is got, back to big-endian. if (self->cacheString) { self->cachedString = str; CBRetainObject(str); // Retain for this object. } return str; // No additional retain. Retained from constructor. } }
bool CBInitMessageByData(CBMessage * self,CBByteArray * data,void (*onErrorReceived)(CBError error,char *,...)){ if (NOT CBInitObject(CBGetObject(self))) return false; self->bytes = data; CBRetainObject(data); // Retain data for this object. self->onErrorReceived = onErrorReceived; self->expectResponse = false; self->serialised = true; return true; }
bool CBInventoryAddInventoryItem(CBInventory * self, CBInventoryItem * item) { bool taken = CBInventoryTakeInventoryItem(self, item); if (taken) CBRetainObject(item); return taken; }
bool CBInitTransactionOutput(CBTransactionOutput * self, uint64_t value, CBScript * script){ if (script){ self->scriptObject = script; CBRetainObject(script); }else self->scriptObject = NULL; self->value = value; if (NOT CBInitMessageByObject(CBGetMessage(self))) return false; return true; }
CBOnMessageReceivedAction CBNodeOnMessageReceived(CBNetworkCommunicator * comm, CBPeer * peer, CBMessage * message){ CBNode * self = CBGetNode(comm); // Add message to queue CBRetainObject(message); CBRetainObject(peer); CBMutexLock(self->messageProcessMutex); if (self->messageQueue == NULL) self->messageQueue = self->messageQueueBack = malloc(sizeof(*self->messageQueueBack)); else{ self->messageQueueBack->next = malloc(sizeof(*self->messageQueueBack)); self->messageQueueBack = self->messageQueueBack->next; } self->messageQueueBack->peer = peer; self->messageQueueBack->message = message; self->messageQueueBack->next = NULL; // Wakeup thread if this is the first in the queue if (self->messageQueue == self->messageQueueBack) // We have just added a block to the queue when there was not one before so wake-up the processing thread. CBConditionSignal(self->messageProcessWaitCond); CBMutexUnlock(self->messageProcessMutex); return CB_MESSAGE_ACTION_CONTINUE; }
bool CBInitVersionChecksumBytesFromString(CBVersionChecksumBytes * self,CBByteArray * string,bool cacheString,void (*logError)(char *,...)) { // Cache string if needed if (cacheString) { self->cachedString = string; CBRetainObject(string); } else self->cachedString = NULL; self->cacheString = cacheString; // Get bytes from string conversion CBBigInt bytes; CBBigIntAlloc(&bytes, 25); // 25 is the number of bytes for bitcoin addresses. if (NOT CBDecodeBase58Checked(&bytes, (char *)CBByteArrayGetData(string), logError)) return false; // Take over the bytes with the CBByteArray if (NOT CBInitByteArrayWithData(CBGetByteArray(self), bytes.data, bytes.length, logError)) return false; CBByteArrayReverseBytes(CBGetByteArray(self)); // CBBigInt is in little-endian. Conversion needed to make bitcoin address the right way. return true; }
bool CBInitVersionChecksumBytesFromString(CBVersionChecksumBytes * self,CBByteArray * string,bool cacheString,CBEvents * events){ // Cache string if needed if (cacheString) { self->cachedString = string; CBRetainObject(string); }else self->cachedString = NULL; self->cacheString = cacheString; // Get bytes from string conversion CBBigInt bytes = CBDecodeBase58Checked((char *)CBByteArrayGetData(string), events); if (bytes.length == 1) { return false; } // Take over the bytes with the CBByteArray if (NOT CBInitByteArrayWithData(CBGetByteArray(self), bytes.data, bytes.length, events)) return false; CBByteArrayReverseBytes(CBGetByteArray(self)); // CBBigInt is in little-endian. Conversion needed to make bitcoin address the right way. return true; }
void CBAlertAddUserAgent(CBAlert * self, CBByteArray * userAgent) { CBRetainObject(userAgent); CBAlertTakeUserAgent(self, userAgent); }
bool CBTransactionAddOutput(CBTransaction * self, CBTransactionOutput * output){ CBRetainObject(output); return CBTransactionTakeOutput(self, output); }
void CBChainDescriptorAddHash(CBChainDescriptor * self, CBByteArray * hash){ CBRetainObject(hash); CBChainDescriptorTakeHash(self, hash); }
void CBNodeDisconnectPeer(CBPeer * peer){ CBRetainObject(peer); CBRunOnEventLoop(CBGetNetworkCommunicator(peer->nodeObj)->eventLoop, CBNodeDisconnectPeerRun, peer, false); }
int main(){ unsigned int s = (unsigned int)time(NULL); s = 1337544566; printf("Session = %ui\n",s); srand(s); // Test genesis block CBByteArray * genesisMerkleRoot = CBNewByteArrayWithDataCopy((uint8_t []){0x3B,0xA3,0xED,0xFD,0x7A,0x7B,0x12,0xB2,0x7A,0xC7,0x2C,0x3E,0x67,0x76,0x8F,0x61,0x7F,0xC8,0x1B,0xC3,0x88,0x8A,0x51,0x32,0x3A,0x9F,0xB8,0xAA,0x4B,0x1E,0x5E,0x4A}, 32, onErrorReceived); CBByteArray * genesisInScript = CBNewByteArrayWithDataCopy((uint8_t [77]){0x04,0xFF,0xFF,0x00,0x1D,0x01,0x04,0x45,0x54,0x68,0x65,0x20,0x54,0x69,0x6D,0x65,0x73,0x20,0x30,0x33,0x2F,0x4A,0x61,0x6E,0x2F,0x32,0x30,0x30,0x39,0x20,0x43,0x68,0x61,0x6E,0x63,0x65,0x6C,0x6C,0x6F,0x72,0x20,0x6F,0x6E,0x20,0x62,0x72,0x69,0x6E,0x6B,0x20,0x6F,0x66,0x20,0x73,0x65,0x63,0x6F,0x6E,0x64,0x20,0x62,0x61,0x69,0x6C,0x6F,0x75,0x74,0x20,0x66,0x6F,0x72,0x20,0x62,0x61,0x6E,0x6B,0x73}, 77, onErrorReceived); CBByteArray * genesisOutScript = CBNewByteArrayWithDataCopy((uint8_t [67]){0x41,0x04,0x67,0x8A,0xFD,0xB0,0xFE,0x55,0x48,0x27,0x19,0x67,0xF1,0xA6,0x71,0x30,0xB7,0x10,0x5C,0xD6,0xA8,0x28,0xE0,0x39,0x09,0xA6,0x79,0x62,0xE0,0xEA,0x1F,0x61,0xDE,0xB6,0x49,0xF6,0xBC,0x3F,0x4C,0xEF,0x38,0xC4,0xF3,0x55,0x04,0xE5,0x1E,0xC1,0x12,0xDE,0x5C,0x38,0x4D,0xF7,0xBA,0x0B,0x8D,0x57,0x8A,0x4C,0x70,0x2B,0x6B,0xF1,0x1D,0x5F,0xAC}, 67, onErrorReceived); // Test hash CBBlock * genesisBlock = CBNewBlockGenesis(onErrorReceived); uint8_t calcHash[32]; CBBlockCalculateHash(genesisBlock,calcHash); if(memcmp(genesisBlock->hash, calcHash,32)){ printf("GENESIS BLOCK HASH FAIL\n0x"); uint8_t * d = genesisBlock->hash; for (int x = 0; x < 32; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = calcHash; for (int x = 0; x < 32; x++) { printf("%.2X",d[x]); } return 1; } // Test deserialised data if (genesisBlock->version != 1) { printf("GENESIS BLOCK VERSION FAIL\n"); return 1; } for (int x = 0; x < 32; x++) { if(CBByteArrayGetByte(genesisBlock->prevBlockHash, x) != 0){ printf("GENESIS BLOCK PREV FAIL\n"); return 1; } } if (CBByteArrayCompare(genesisBlock->merkleRoot, genesisMerkleRoot)) { printf("GENESIS BLOCK MERKLE ROOT FAIL\n0x"); uint8_t * d = CBByteArrayGetData(genesisBlock->merkleRoot); for (int x = 0; x < 32; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = CBByteArrayGetData(genesisMerkleRoot); for (int x = 0; x < 32; x++) { printf("%.2X",d[x]); } return 1; } if (genesisBlock->time != 1231006505) { printf("GENESIS BLOCK TIME FAIL\n0x"); return 1; } if (genesisBlock->target != 0x1D00FFFF) { printf("GENESIS BLOCK DIFFICULTY FAIL\n0x"); return 1; } if (genesisBlock->nonce != 2083236893) { printf("GENESIS BLOCK DIFFICULTY FAIL\n0x"); return 1; } if (genesisBlock->transactionNum != 1) { printf("GENESIS BLOCK TRANSACTION NUM FAIL\n0x"); return 1; } CBTransaction * genesisCoinBase = genesisBlock->transactions[0]; if (genesisCoinBase->inputNum != 1) { printf("GENESIS BLOCK TRANSACTION INPUT NUM FAIL\n0x"); return 1; } if (genesisCoinBase->outputNum != 1) { printf("GENESIS BLOCK TRANSACTION OUTPUT NUM FAIL\n0x"); return 1; } if (genesisCoinBase->version != 1) { printf("GENESIS BLOCK TRANSACTION VERSION FAIL\n0x"); return 1; } if (genesisCoinBase->lockTime != 0) { printf("GENESIS BLOCK TRANSACTION LOCK TIME FAIL\n0x"); return 1; } if (genesisCoinBase->inputs[0]->scriptObject->length != 0x4D) { printf("GENESIS BLOCK TRANSACTION INPUT SCRIPT LENGTH FAIL\n0x"); return 1; } if (genesisCoinBase->outputs[0]->scriptObject->length != 0x43) { printf("GENESIS BLOCK TRANSACTION OUTPUT SCRIPT LENGTH FAIL\n0x"); return 1; } for (int x = 0; x < 32; x++) { if(CBByteArrayGetByte(genesisCoinBase->inputs[0]->prevOut.hash, x) != 0){ printf("GENESIS BLOCK TRANSACTION INPUT OUT POINTER HASH FAIL\n"); return 1; } } if (genesisCoinBase->inputs[0]->prevOut.index != 0xFFFFFFFF) { printf("GENESIS BLOCK TRANSACTION INPUT OUT POINTER INDEX FAIL\n0x"); return 1; } if (genesisCoinBase->inputs[0]->sequence != CB_TRANSACTION_INPUT_FINAL) { printf("GENESIS BLOCK TRANSACTION INPUT SEQUENCE FAIL\n0x"); return 1; } if (CBByteArrayCompare(genesisCoinBase->inputs[0]->scriptObject, genesisInScript)) { printf("GENESIS BLOCK IN SCRIPT FAIL\n0x"); uint8_t * d = CBByteArrayGetData(genesisCoinBase->inputs[0]->scriptObject); for (int x = 0; x < genesisCoinBase->inputs[0]->scriptObject->length; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = CBByteArrayGetData(genesisInScript); for (int x = 0; x < genesisInScript->length; x++) { printf("%.2X",d[x]); } return 1; } if (genesisCoinBase->outputs[0]->value != 5000000000) { printf("GENESIS BLOCK TRANSACTION OUTPUT VALUE FAIL\n0x"); return 1; } if (CBByteArrayCompare(genesisCoinBase->outputs[0]->scriptObject, genesisOutScript)) { printf("GENESIS BLOCK OUT SCRIPT FAIL\n0x"); uint8_t * d = CBByteArrayGetData(genesisCoinBase->outputs[0]->scriptObject); for (int x = 0; x < genesisCoinBase->outputs[0]->scriptObject->length; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = CBByteArrayGetData(genesisOutScript); for (int x = 0; x < genesisOutScript->length; x++) { printf("%.2X",d[x]); } return 1; } // Test serialisation into genesis block CBBlock * block = CBNewBlock(onErrorReceived); block->version = 1; uint8_t * zeroHash = malloc(32); memset(zeroHash, 0, 32); block->prevBlockHash = CBNewByteArrayWithData(zeroHash, 32, onErrorReceived); block->merkleRoot = genesisMerkleRoot; block->target = 0x1D00FFFF; block->time = 1231006505; block->nonce = 2083236893; block->transactionNum = 1; block->transactions = malloc(sizeof(*block->transactions)); block->transactions[0] = CBNewTransaction(0, 1, onErrorReceived); CBRetainObject(block->prevBlockHash); // Retain for the zero hash in the input CBTransactionTakeInput(block->transactions[0], CBNewTransactionInput(genesisInScript, CB_TRANSACTION_INPUT_FINAL, block->prevBlockHash, 0xFFFFFFFF, onErrorReceived)); CBTransactionTakeOutput(block->transactions[0], CBNewTransactionOutput(5000000000, genesisOutScript, onErrorReceived)); CBGetMessage(block)->bytes = CBNewByteArrayOfSize(CBGetMessage(genesisBlock)->bytes->length, onErrorReceived); CBBlockSerialise(block, true, true); if (CBByteArrayCompare(CBGetMessage(block)->bytes, CBGetMessage(genesisBlock)->bytes)) { printf("SERIALISATION TO GENESIS BLOCK FAIL\n0x"); uint8_t * d = CBByteArrayGetData(CBGetMessage(block)->bytes); for (int x = 0; x < CBGetMessage(block)->bytes->length; x++) { printf("%.2X",d[x]); } printf("\n!=\n0x"); d = CBByteArrayGetData(CBGetMessage(genesisBlock)->bytes); for (int x = 0; x < CBGetMessage(genesisBlock)->bytes->length; x++) { printf("%.2X",d[x]); } return 1; } CBReleaseObject(genesisBlock); // ??? Add tests for non-genesis blocks return 0; }
void CBBlockHeadersAddBlockHeader(CBBlockHeaders * self, CBBlock * header){ CBRetainObject(header); CBBlockHeadersTakeBlockHeader(self, header); }
bool CBAddressBroadcastAddNetworkAddress(CBAddressBroadcast * self,CBNetworkAddress * address){ CBRetainObject(address); return CBAddressBroadcastTakeNetworkAddress(self,address); }
bool CBTransactionAddInput(CBTransaction * self, CBTransactionInput * input){ CBRetainObject(input); return CBTransactionTakeInput(self, input); }
void CBInitTransactionInput(CBTransactionInput * self, CBScript * script, uint32_t sequence, CBByteArray * prevOutHash, uint32_t prevOutIndex){ if (script) CBRetainObject(script); CBRetainObject(prevOutHash); CBInitTransactionInputTakeScriptAndHash(self, script, sequence, prevOutHash, prevOutIndex); }
void CBNetworkAddressListAddNetworkAddress(CBNetworkAddressList * self, CBNetworkAddress * address){ CBRetainObject(address); CBNetworkAddressListTakeNetworkAddress(self, address); }
bool CBBlockHeadersAddBlockHeader(CBBlockHeaders * self,CBBlock * header) { CBRetainObject(header); return CBBlockHeadersTakeBlockHeader(self,header); }