uint32_t CBTransactionOutputSerialise(CBTransactionOutput * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to serialise a CBTransactionInput with no bytes."); return 0; } if (NOT self->scriptObject){ CBLogError("Attempting to serialise a CBTransactionOutput without scriptObject."); return 0; } CBVarInt scriptLen = CBVarIntFromUInt64(CBGetByteArray(self->scriptObject)->length); uint32_t reqLen = 8 + scriptLen.size + CBGetByteArray(self->scriptObject)->length; if (bytes->length < reqLen) { CBLogError("Attempting to serialise a CBTransactionOutput with less bytes than required. %i < %i", bytes->length, reqLen); return 0; } // Serialise data into the CBByteArray and rereference objects to this CBByteArray to save memory. CBByteArraySetInt64(bytes, 0, self->value); CBVarIntEncode(bytes, 8, scriptLen); CBByteArrayCopyByteArray(bytes, 8 + scriptLen.size, CBGetByteArray(self->scriptObject)); CBByteArrayChangeReference(CBGetByteArray(self->scriptObject), bytes, 8 + scriptLen.size); // Ensure length is correct bytes->length = reqLen; // Is serialised. CBGetMessage(self)->serialised = true; return reqLen; }
uint32_t CBTransactionInputSerialise(CBTransactionInput * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_NULL_BYTES,"Attempting to serialise a CBTransactionInput with no bytes."); return 0; } if (NOT self->prevOut.hash){ CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_DATA,"Attempting to serialise a CBTransactionInput without prevOut.hash."); return 0; } if (NOT self->scriptObject){ CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_DATA,"Attempting to serialise a CBTransactionInput without scriptObject."); return 0; } CBVarInt scriptLen = CBVarIntFromUInt64(CBGetByteArray(self->scriptObject)->length); uint32_t reqLen = 40 + scriptLen.size + CBGetByteArray(self->scriptObject)->length; if (bytes->length < reqLen) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"Attempting to serialise a CBTransactionInput with less bytes than required. %i < %i\n",bytes->length, reqLen); return 0; } // Serialise data into the CBByteArray and rereference objects to this CBByteArray to save memory. CBByteArrayCopyByteArray(bytes, 0, self->prevOut.hash); CBByteArrayChangeReference(self->prevOut.hash, bytes, 0); CBByteArraySetInt32(bytes, 32, self->prevOut.index); CBVarIntEncode(bytes, 36, scriptLen); CBByteArrayCopyByteArray(bytes, 36 + scriptLen.size,CBGetByteArray(self->scriptObject)); CBByteArrayChangeReference(CBGetByteArray(self->scriptObject),bytes,36 + scriptLen.size); CBByteArraySetInt32(bytes,36 + scriptLen.size + CBGetByteArray(self->scriptObject)->length,self->sequence); CBGetMessage(self)->serialised = true; return reqLen; }
uint32_t CBInventoryBroadcastSerialise(CBInventoryBroadcast * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_NULL_BYTES,"Attempting to serialise a CBInventoryBroadcast with no bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->itemNum); if (bytes->length < num.size + 36 * self->itemNum) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBInventoryBroadcast with less bytes than required."); return 0; } CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint16_t x = 0; x < num.val; x++) { CBGetMessage(self->items[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); uint32_t len = CBInventoryItemSerialise(self->items[x]); if (NOT len) { CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"CBInventoryBroadcast cannot be serialised because of an error with the CBInventoryItem number %u.",x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) { CBReleaseObject(CBGetMessage(self->items[y])->bytes); } return 0; } CBGetMessage(self->items[x])->bytes->length = len; cursor += len; } return cursor; }
uint32_t CBBlockHeadersSerialise(CBBlockHeaders * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBBlockHeaders with no bytes."); return 0; } if (bytes->length < 81 * self->headerNum) { CBLogError("Attempting to deserialise a CBBlockHeaders with less bytes than minimally required."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->headerNum); CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint16_t x = 0; x < num.val; x++) { if (! CBGetMessage(self->blockHeaders[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as the block headers message, re-serialise the block header, in case it got overwritten. || CBGetMessage(self->blockHeaders[x])->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(self->blockHeaders[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->blockHeaders[x])->bytes); CBGetMessage(self->blockHeaders[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (! CBGetMessage(self->blockHeaders[x])->bytes) { CBLogError("Cannot create a new CBByteArray sub reference in CBBlockHeadersSerialise for the header number %u", x); return 0; } if (! CBBlockSerialise(self->blockHeaders[x], false, force)) { // false for no transactions. CBLogError("CBBlockHeaders cannot be serialised because of an error with the CBBlock number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->blockHeaders[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->blockHeaders[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->blockHeaders[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->blockHeaders[x])->bytes->length; } // Ensure length is correct bytes->length = cursor; // Is now serialised CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBNetworkAddressListSerialise(CBNetworkAddressList * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBNetworkAddress with no bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->addrNum); if (bytes->length < (26 + self->timeStamps * 4) * self->addrNum + num.size) { CBLogError("Attempting to serialise a CBNetworkAddress without enough bytes."); return 0; } CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint8_t x = 0; x < num.val; x++) { if (! CBGetMessage(self->addresses[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as this address broadcast, re-serialise the address, in case it got overwritten. || CBGetMessage(self->addresses[x])->bytes->sharedData == bytes->sharedData || (CBGetMessage(self->addresses[x])->bytes->length != 26) ^ self->timeStamps) { if (CBGetMessage(self->addresses[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->addresses[x])->bytes); CBGetMessage(self->addresses[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (! CBNetworkAddressSerialise(self->addresses[x], self->timeStamps)) { CBLogError("CBNetworkAddress cannot be serialised because of an error with the CBNetworkAddress number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->addresses[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->addresses[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->addresses[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->addresses[x])->bytes->length; } // Change bytes length bytes->length = cursor; // Is now serialised CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBBlockHeadersSerialise(CBBlockHeaders * self, bool force) { CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->logError("Attempting to serialise a CBBlockHeaders with no bytes."); return 0; } if (bytes->length < 81 * self->headerNum) { CBGetMessage(self)->logError("Attempting to deserialise a CBBlockHeaders with less bytes than minimally required."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->headerNum); CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint16_t x = 0; x < num.val; x++) { if (force && CBGetMessage(self->blockHeaders[x])->serialised) CBReleaseObject(CBGetMessage(self->blockHeaders[x])->bytes); if (NOT CBGetMessage(self->blockHeaders[x])->serialised || force) { CBGetMessage(self->blockHeaders[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->blockHeaders[x])->bytes) { CBGetMessage(self)->logError("Cannot create a new CBByteArray sub reference in CBBlockHeadersSerialise for the header number %u",x); return 0; } uint32_t len = CBBlockSerialise(self->blockHeaders[x], false, force); // false for no transactions. if (NOT len) { CBGetMessage(self)->logError("CBBlockHeaders cannot be serialised because of an error with the CBBlock number %u.",x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->blockHeaders[y])->bytes); return 0; } CBGetMessage(self->blockHeaders[x])->bytes->length = len; } else if (CBGetMessage(self->blockHeaders[x])->bytes->sharedData != bytes->sharedData) { // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->blockHeaders[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->blockHeaders[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->blockHeaders[x])->bytes->length; } CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBInventoryBroadcastSerialise(CBInventoryBroadcast * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_NULL_BYTES,"Attempting to serialise a CBInventoryBroadcast with no bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->itemNum); if (bytes->length < num.size + 36 * self->itemNum) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBInventoryBroadcast with less bytes than required."); return 0; } CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint16_t x = 0; x < num.val; x++) { if (force && CBGetMessage(self->items[x])->serialised) CBReleaseObject(CBGetMessage(self->items[x])->bytes); if (NOT CBGetMessage(self->items[x])->serialised || force) { CBGetMessage(self->items[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->items[x])->bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_INIT_FAIL,"Cannot create a new CBByteArray sub reference in CBInventoryBroadcastSerialise"); return 0; } uint32_t len = CBInventoryItemSerialise(self->items[x]); if (NOT len) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"CBInventoryBroadcast cannot be serialised because of an error with the CBInventoryItem number %u.",x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->items[y])->bytes); return 0; } CBGetMessage(self->items[x])->bytes->length = len; }else if (CBGetMessage(self->items[x])->bytes->sharedData != bytes->sharedData){ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->items[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->items[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->items[x])->bytes->length; } CBGetMessage(self)->serialised = true; return cursor; }
uint16_t CBChainDescriptorSerialise(CBChainDescriptor * self){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (! bytes) { CBLogError("Attempting to serialise a CBChainDescriptor with no bytes."); return 0; } CBVarInt hashNum = CBVarIntFromUInt64(self->hashNum); if (bytes->length < hashNum.size + self->hashNum * 32) { CBLogError("Attempting to serialise a CBChainDescriptor with less bytes than required for the hashes."); return 0; } CBVarIntEncode(bytes, 0, hashNum); uint16_t cursor = hashNum.size; for (uint16_t x = 0; x < self->hashNum; x++) { CBByteArrayCopyByteArray(bytes, cursor, self->hashes[x]); CBByteArrayChangeReference(self->hashes[x], bytes, cursor); cursor += 32; } CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBAddressBroadcastSerialise(CBAddressBroadcast * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_NULL_BYTES,"Attempting to serialise a CBAddressBroadcast with no bytes."); return 0; } if (bytes->length < (26 + self->timeStamps * 4) * self->addrNum) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"Attempting to serialise a CBAddressBroadcast without enough bytes."); return 0; } CBVarInt num = CBVarIntFromUInt64(self->addrNum); CBVarIntEncode(bytes, 0, num); uint16_t cursor = num.size; for (uint8_t x = 0; x < num.val; x++) { if (force && CBGetMessage(self->addresses[x])->serialised) CBReleaseObject(CBGetMessage(self->addresses[x])->bytes); if (NOT CBGetMessage(self->addresses[x])->serialised || force) { CBGetMessage(self->addresses[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); uint32_t len = CBNetworkAddressSerialise(self->addresses[x],self->timeStamps); if (NOT len) { CBGetMessage(self)->onErrorReceived(CB_ERROR_MESSAGE_SERIALISATION_BAD_BYTES,"CBAddressBroadcast cannot be serialised because of an error with the CBNetworkAddress number %u.",x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint8_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->addresses[y])->bytes); return 0; } CBGetMessage(self->addresses[x])->bytes->length = len; }else if (CBGetMessage(self->addresses[x])->bytes->sharedData != bytes->sharedData){ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->addresses[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->addresses[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->addresses[x])->bytes->length; } CBGetMessage(self)->serialised = true; return cursor; }
uint32_t CBTransactionSerialise(CBTransaction * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to serialise a CBTransaction with no bytes. Now that you think about it, that was a bit stupid wasn't it?"); return 0; } if (NOT self->inputNum || NOT self->outputNum) { CBLogError("Attempting to serialise a CBTransaction with an empty output or input list."); return 0; } CBVarInt inputNum = CBVarIntFromUInt64(self->inputNum); CBVarInt outputNum = CBVarIntFromUInt64(self->outputNum); uint32_t cursor = 4 + inputNum.size; if (bytes->length < cursor + 5) { CBLogError("Attempting to serialise a CBTransaction with less bytes than required. %i < %i\n", bytes->length, cursor + 5); return 0; } // Serialise data into the CBByteArray and rereference objects to this CBByteArray to save memory. CBByteArraySetInt32(bytes, 0, self->version); CBVarIntEncode(bytes, 4, inputNum); for (uint32_t x = 0; x < self->inputNum; x++) { if (NOT CBGetMessage(self->inputs[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as this transaction, re-serialise the input, in case it got overwritten. || CBGetMessage(self->inputs[x])->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(self->inputs[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->inputs[x])->bytes); CBGetMessage(self->inputs[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->inputs[x])->bytes) { CBLogError("Cannot create a new CBByteArray sub reference in CBTransactionSerialise for input number %u", x); return 0; } if (NOT CBTransactionInputSerialise(self->inputs[x])) { CBLogError("CBTransaction cannot be serialised because of an error with the input number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint32_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->inputs[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->inputs[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->inputs[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->inputs[x])->bytes->length; } if (bytes->length < cursor + 5) { // Check room for output number and lockTime. CBLogError("Attempting to serialise a CBTransaction with less bytes than required for output number and the lockTime. %i < %i", bytes->length, cursor + 5); return 0; } CBVarIntEncode(bytes, cursor, outputNum); cursor += outputNum.size; for (uint32_t x = 0; x < self->outputNum; x++) { if (NOT CBGetMessage(self->outputs[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as this transaction, re-serialise the output, in case it got overwritten. || CBGetMessage(self->outputs[x])->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(self->outputs[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->outputs[x])->bytes); CBGetMessage(self->outputs[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->outputs[x])->bytes) { CBLogError("Cannot create a new CBByteArray sub reference in CBTransactionSerialise for output number %u", x); return 0; } if (NOT CBTransactionOutputSerialise(self->outputs[x])) { CBLogError("CBTransaction cannot be serialised because of an error with the output number %u.", x); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint32_t y = 0; y < self->inputNum; y++) CBReleaseObject(CBGetMessage(self->inputs[y])->bytes); for (uint32_t y = 0; y < x + 1; y++) CBReleaseObject(CBGetMessage(self->outputs[y])->bytes); return 0; } }else{ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->outputs[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->outputs[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->outputs[x])->bytes->length; } if (bytes->length < cursor + 4) { // Check room for lockTime. CBLogError("Attempting to serialise a CBTransaction with less bytes than required for the lockTime. %i < %i\n", bytes->length, cursor + 4); // Release CBByteArray objects to avoid problems overwritting pointer without release, if serialisation is tried again. for (uint32_t y = 0; y < self->inputNum; y++) CBReleaseObject(CBGetMessage(self->inputs[y])->bytes); for (uint32_t y = 0; y < self->outputNum; y++) CBReleaseObject(CBGetMessage(self->outputs[y])->bytes); return 0; } CBByteArraySetInt32(bytes, cursor, self->lockTime); // Ensure length is correct bytes->length = cursor + 4; // Is serialised CBGetMessage(self)->serialised = true; // Make the hash not set for this serialisation. self->hashSet = false; return cursor + 4; }
CBGetHashReturn CBTransactionGetInputHashForSignature(void * vself, CBByteArray * prevOutSubScript, uint32_t input, CBSignType signType, uint8_t * hash){ CBTransaction * self= vself; if (self->inputNum < input + 1) { CBLogError("Receiving transaction hash to sign cannot be done for because the input index goes past the number of inputs."); return CB_TX_HASH_BAD; } uint8_t last5Bits = (signType & 0x1f); // For some reason this is what the C++ client does. CBVarInt prevOutputSubScriptVarInt = CBVarIntFromUInt64(prevOutSubScript->length); uint32_t sizeOfData = 12 + prevOutSubScript->length + prevOutputSubScriptVarInt.size; // Version, lock time and the sign type make up 12 bytes. if (signType & CB_SIGHASH_ANYONECANPAY) { sizeOfData += 41; // Just this one input. 32 bytes for outPointerHash, 4 for outPointerIndex, 4 for sequence and one for the *inputNum* var int }else{ sizeOfData += CBVarIntSizeOf(self->inputNum) + self->inputNum * 41 - 1; // All inputs with 1 byte var int except one. } if (last5Bits == CB_SIGHASH_NONE){ sizeOfData++; // Just for the CBVarInt and no outputs. }else if ((signType & 0x1f) == CB_SIGHASH_SINGLE){ if (self->outputNum < input + 1) { CBLogError("Receiving transaction hash to sign cannot be done for CB_SIGHASH_SINGLE because there are not enough outputs."); return CB_TX_HASH_BAD; } sizeOfData += CBVarIntSizeOf(input + 1) + input * 9; // For outputs up to the input index // The size for the output at the input index. uint32_t len = CBGetByteArray(self->outputs[input]->scriptObject)->length; sizeOfData += 8 + CBVarIntSizeOf(len) + len; }else{ // All outputs. Default to SIGHASH_ALL sizeOfData += CBVarIntSizeOf(self->outputNum); for (uint32_t x = 0; x < self->outputNum; x++) { uint32_t len = CBGetByteArray(self->outputs[x]->scriptObject)->length; sizeOfData += 8 + CBVarIntSizeOf(len) + len; } } CBByteArray * data = CBNewByteArrayOfSize(sizeOfData); if (NOT data) return CB_TX_HASH_ERR; CBByteArraySetInt32(data, 0, self->version); // Copy input data. Scripts are not copied for the inputs. uint32_t cursor; if (signType & CB_SIGHASH_ANYONECANPAY) { CBVarIntEncode(data, 4, CBVarIntFromUInt64(1)); // Only the input the signature is for. CBByteArrayCopyByteArray(data, 5, self->inputs[input]->prevOut.hash); CBByteArraySetInt32(data, 37, self->inputs[input]->prevOut.index); // Add prevOutSubScript CBVarIntEncode(data, 41, prevOutputSubScriptVarInt); cursor = 41 + prevOutputSubScriptVarInt.size; CBByteArrayCopyByteArray(data, cursor, prevOutSubScript); cursor += prevOutSubScript->length; CBByteArraySetInt32(data, cursor, self->inputs[input]->sequence); cursor += 4; }else{ CBVarInt inputNum = CBVarIntFromUInt64(self->inputNum); CBVarIntEncode(data, 4, inputNum); cursor = 4 + inputNum.size; for (uint32_t x = 0; x < self->inputNum; x++) { CBByteArrayCopyByteArray(data, cursor, self->inputs[x]->prevOut.hash); cursor += 32; CBByteArraySetInt32(data, cursor, self->inputs[x]->prevOut.index); cursor += 4; // Add prevOutSubScript if the input is for the signature. if (x == input) { CBVarIntEncode(data, cursor, prevOutputSubScriptVarInt); cursor += prevOutputSubScriptVarInt.size; CBByteArrayCopyByteArray(data, cursor, prevOutSubScript); cursor += prevOutSubScript->length; }else{ CBVarIntEncode(data, cursor, CBVarIntFromUInt64(0)); cursor++; } if ((signType == CB_SIGHASH_NONE || signType == CB_SIGHASH_SINGLE) && x != input) { CBByteArraySetInt32(data, cursor, 0); } else // SIGHASH_ALL or input index for signing sequence CBByteArraySetInt32(data, cursor, self->inputs[x]->sequence); cursor += 4; } } // Copy output data if (last5Bits == CB_SIGHASH_NONE){ CBVarInt varInt = CBVarIntFromUInt64(0); CBVarIntEncode(data, cursor, varInt); cursor++; }else if (last5Bits == CB_SIGHASH_SINGLE){ CBVarInt varInt = CBVarIntFromUInt64(input + 1); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; for (uint32_t x = 0; x < input; x++) { CBByteArraySetInt64(data, cursor, CB_OUTPUT_VALUE_MINUS_ONE); cursor += 8; CBVarIntEncode(data, cursor, CBVarIntFromUInt64(0)); cursor++; } CBByteArraySetInt64(data, cursor, self->outputs[input]->value); cursor += 8; varInt = CBVarIntFromUInt64(CBGetByteArray(self->outputs[input]->scriptObject)->length); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; CBByteArrayCopyByteArray(data, cursor, CBGetByteArray(self->outputs[input]->scriptObject)); cursor += varInt.val; }else{ // SIGHASH_ALL CBVarInt varInt = CBVarIntFromUInt64(self->outputNum); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; for (uint32_t x = 0; x < self->outputNum; x++) { CBByteArraySetInt64(data, cursor, self->outputs[x]->value); cursor += 8; varInt = CBVarIntFromUInt64(CBGetByteArray(self->outputs[x]->scriptObject)->length); CBVarIntEncode(data, cursor, varInt); cursor += varInt.size; CBByteArrayCopyByteArray(data, cursor, CBGetByteArray(self->outputs[x]->scriptObject)); cursor += varInt.val; } } // Set lockTime CBByteArraySetInt32(data, cursor, self->lockTime); CBByteArraySetInt32(data, cursor + 4, signType); assert(sizeOfData == cursor + 8); // Must always be like this uint8_t firstHash[32]; CBSha256(CBByteArrayGetData(data), sizeOfData, firstHash); CBSha256(firstHash, 32, hash); return CB_TX_HASH_OK; }
uint32_t CBVersionSerialise(CBVersion * self, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBGetMessage(self)->logError("Attempting to serialise a CBVersion with no bytes."); return 0; } if (bytes->length < 46) { CBGetMessage(self)->logError("Attempting to serialise a CBVersion with less than 46 bytes."); return 0; } CBByteArraySetInt32(bytes, 0, self->version); CBByteArraySetInt64(bytes, 4, self->services); CBByteArraySetInt64(bytes, 12, self->time); if (force && CBGetMessage(self->addRecv)->serialised) CBReleaseObject(CBGetMessage(self->addRecv)->bytes); if (NOT CBGetMessage(self->addRecv)->serialised || force) { CBGetMessage(self->addRecv)->bytes = CBByteArraySubReference(bytes, 20, bytes->length-20); if (NOT CBGetMessage(self->addRecv)->bytes) { CBGetMessage(self)->logError("Cannot create a new CBByteArray sub reference in CBVersionSerialise for receiving address."); return 0; } uint32_t len = CBNetworkAddressSerialise(self->addRecv,false); if (NOT len) { CBGetMessage(self)->logError("CBVersion cannot be serialised because of an error with the receiving CBNetworkAddress"); // Release bytes to avoid problems overwritting pointer without release, if serialisation is tried again. CBReleaseObject(CBGetMessage(self->addRecv)->bytes); return 0; } CBGetMessage(self->addRecv)->bytes->length = len; }else if (CBGetMessage(self->addRecv)->bytes->sharedData != bytes->sharedData){ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, 20, CBGetMessage(self->addRecv)->bytes); CBByteArrayChangeReference(CBGetMessage(self->addRecv)->bytes, bytes, 20); } if (self->version >= 106) { if (bytes->length < 85) { CBGetMessage(self)->logError("Attempting to serialise a CBVersion with less than 85 bytes required."); return 0; } if (self->userAgent->length > 400) { CBGetMessage(self)->logError("Attempting to serialise a CBVersion with a userAgent over 400 bytes."); return 0; } if (force && CBGetMessage(self->addSource)->serialised) CBReleaseObject(CBGetMessage(self->addSource)->bytes); if (NOT CBGetMessage(self->addSource)->serialised || force) { CBGetMessage(self->addSource)->bytes = CBByteArraySubReference(bytes, 46, bytes->length-46); if (NOT CBGetMessage(self->addSource)->bytes) { CBGetMessage(self)->logError("Cannot create a new CBByteArray sub reference in CBVersionSerialise for source address."); return 0; } uint32_t len = CBNetworkAddressSerialise(self->addSource,false); if (NOT len) { CBGetMessage(self)->logError("CBVersion cannot be serialised because of an error with the source CBNetworkAddress"); // Release bytes to avoid problems overwritting pointer without release, if serialisation is tried again. CBReleaseObject(CBGetMessage(self->addSource)->bytes); return 0; } CBGetMessage(self->addSource)->bytes->length = len; }else if (CBGetMessage(self->addSource)->bytes->sharedData != bytes->sharedData){ // Move serialsed data to one location CBByteArrayCopyByteArray(bytes, 46, CBGetMessage(self->addSource)->bytes); CBByteArrayChangeReference(CBGetMessage(self->addSource)->bytes, bytes, 46); } CBByteArraySetInt64(bytes, 72, self->nonce); CBVarInt varInt = CBVarIntFromUInt64(self->userAgent->length); CBVarIntEncode(bytes, 80, varInt); if (bytes->length < 84 + varInt.size + varInt.val) { CBGetMessage(self)->logError("Attempting to deserialise a CBVersion without enough space to cover the userAgent and block height."); return 0; } CBByteArrayCopyByteArray(bytes, 80 + varInt.size,self->userAgent); CBByteArrayChangeReference(self->userAgent,bytes,80 + varInt.size); CBByteArraySetInt32(bytes, 80 + varInt.size + (uint32_t)varInt.val, self->blockHeight); CBGetMessage(self)->serialised = true; return 84 + varInt.size + (uint32_t)varInt.val; }else{ // Not the further message. CBGetMessage(self)->serialised = true; return 46; } }
uint32_t CBBlockSerialise(CBBlock * self, bool transactions, bool force){ CBByteArray * bytes = CBGetMessage(self)->bytes; if (NOT bytes) { CBLogError("Attempting to serialise a CBBlock with no bytes."); return 0; } CBVarInt transactionNum = CBVarIntFromUInt64(self->transactionNum); uint32_t cursor = 80 + transactionNum.size; if (bytes->length < cursor + 1) { CBLogError("Attempting to serialise a CBBlock with less bytes than required for the header, transaction number var int and at least a null byte. %i < %i", bytes->length, cursor + 1); return 0; } // Do header CBByteArraySetInt32(bytes, 0, self->version); CBByteArrayCopyByteArray(bytes, 4, self->prevBlockHash); CBByteArrayChangeReference(self->prevBlockHash, bytes, 4); CBByteArrayCopyByteArray(bytes, 36, self->merkleRoot); CBByteArrayChangeReference(self->merkleRoot, bytes, 36); CBByteArraySetInt32(bytes, 68, self->time); CBByteArraySetInt32(bytes, 72, self->target); CBByteArraySetInt32(bytes, 76, self->nonce); // Do Transactions CBVarIntEncode(bytes, 80, transactionNum); if (transactions) { for (uint32_t x = 0; x < self->transactionNum; x++) { if (NOT CBGetMessage(self->transactions[x])->serialised // Serailise if not serialised yet. // Serialise if force is true. || force // If the data shares the same data as this block, re-serialise the transaction, in case it got overwritten. || CBGetMessage(self->transactions[x])->bytes->sharedData == bytes->sharedData) { if (CBGetMessage(self->transactions[x])->serialised) // Release old byte array CBReleaseObject(CBGetMessage(self->transactions[x])->bytes); CBGetMessage(self->transactions[x])->bytes = CBByteArraySubReference(bytes, cursor, bytes->length-cursor); if (NOT CBGetMessage(self->transactions[x])->bytes) { CBLogError("Cannot create a new CBByteArray sub reference in CBBlockSerialise for the transaction number %u", x); return 0; } if (NOT CBTransactionSerialise(self->transactions[x], force)) { CBLogError("CBBlock cannot be serialised because of an error with the transaction number %u.", x); return 0; } }else{ // Move serialsed data to one location if (bytes->length < cursor + CBGetMessage(self->transactions[x])->bytes->length) { CBLogError("CBBlock cannot be serialised because there was not enough bytes for the transaction number %u (%u < %u).", x, bytes->length, cursor + CBGetMessage(self->transactions[x])->bytes->length); return 0; } CBByteArrayCopyByteArray(bytes, cursor, CBGetMessage(self->transactions[x])->bytes); CBByteArrayChangeReference(CBGetMessage(self->transactions[x])->bytes, bytes, cursor); } cursor += CBGetMessage(self->transactions[x])->bytes->length; } }else{ // Add null byte since there are to be no transactions (header only). CBByteArraySetByte(bytes, cursor, 0); cursor++; } // Reset hash self->hashSet = false; // Ensure data length is correct. bytes->length = cursor; // Is now serialised. CBGetMessage(self)->serialised = true; return cursor; }