From 6448e7bec9b80e0db95acdd1af01abed757ce0fc Mon Sep 17 00:00:00 2001 From: rustammendel Date: Mon, 13 Jun 2022 16:40:13 +0200 Subject: [PATCH] item-16 | Fix Outputs - Fixed addDatumOption cannot receive data in chunks - Fixed addReferenceScript cannot receive data in chunks - Fixed comments for output methods - Fix tests --- src/txHashBuilder.c | 181 ++++++++++++++++++++++++++++----------- src/txHashBuilder.h | 19 +++- src/txHashBuilder_test.c | 29 +++++-- 3 files changed, 170 insertions(+), 59 deletions(-) diff --git a/src/txHashBuilder.c b/src/txHashBuilder.c index 07c31f51..8b1a1437 100644 --- a/src/txHashBuilder.c +++ b/src/txHashBuilder.c @@ -80,7 +80,7 @@ static void cbor_append_legacy_txOutput(tx_hash_builder_t *builder, tx_hash_buil // Array(2 + includeDatumHash)[ // Bytes[address] // Unsigned[amount] - // //// entries added later, datum hash + // //optional entry added later, datum_hash = $hash32 // ] BUILDER_APPEND_CBOR(CBOR_TYPE_ARRAY, 2 + output->includeDatumOption); { @@ -93,7 +93,7 @@ static void cbor_append_legacy_txOutput(tx_hash_builder_t *builder, tx_hash_buil builder->state = TX_HASH_BUILDER_IN_OUTPUTS_TOP_LEVEL_DATA; } else { builder->multiassetData.remainingAssetGroups = output->numAssetGroups; - // Array(2)[ + // Array(2 + includeDatumHash)[ // Bytes[address] // Array(2)[] // Unsigned[amount] @@ -101,6 +101,7 @@ static void cbor_append_legacy_txOutput(tx_hash_builder_t *builder, tx_hash_buil // // entries added later, { * policy_id => { * asset_name => uint } } // ] // ] + // //optional entry added later, datum_hash = $hash32 // ] { BUILDER_APPEND_CBOR(CBOR_TYPE_ARRAY, 2 + output->includeDatumOption); @@ -122,22 +123,28 @@ static void cbor_append_legacy_txOutput(tx_hash_builder_t *builder, tx_hash_buil static void cbor_append_post_alonzo_txOutput(tx_hash_builder_t *builder, tx_hash_builder_output const *output) { + ASSERT(output->format == POST_ALONZO); + // Map(2 + includeDatumOption + includeScriptRef)[ + // Unsigned[0] ; entry key // Bytes[address] - // Unsigned[amount] - // Array (2)[ - // Unsigned[option] - // Bytes[buffer] ; hash or plutus data - // ] - // Bytes[script_ref] ;script_ref - // ] + BUILDER_APPEND_CBOR(CBOR_TYPE_MAP, 2 + output->includeDatumOption + output->includeScriptRef); + { + BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, TX_OUTPUT_KEY_ADDRESS); + } + { + BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, output->addressSize); + BUILDER_APPEND_DATA(output->addressBuffer, output->addressSize); + } + { + BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, TX_OUTPUT_KEY_VALUE); + } if (output->numAssetGroups == 0) { - - BUILDER_APPEND_CBOR(CBOR_TYPE_MAP, 2 + output->includeDatumOption + output->includeScriptRef); - { - BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, output->addressSize); - BUILDER_APPEND_DATA(output->addressBuffer, output->addressSize); - } + // Unsigned[0] ; entry key + // Unsigned[amount] + // //optional entry added later, datum_option = [ 0, $hash32 // 1, data ] + // //optional entry added later, script_ref = #6.24(bytes .cbor script) + // ] { BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, output->amount); } @@ -145,27 +152,21 @@ static void cbor_append_post_alonzo_txOutput(tx_hash_builder_t *builder, tx_hash builder->state = TX_HASH_BUILDER_IN_OUTPUTS_TOP_LEVEL_DATA; } else { builder->multiassetData.remainingAssetGroups = output->numAssetGroups; - // Map(2 + includeDatumOption + includeScriptRef)[ - // Bytes[address] - // Array(2)[] + // Unsigned[0] ; entry key + // Array(2)[ // Unsigned[amount] // Map(numAssetGroups)[ // // entries added later, { * policy_id => { * asset_name => uint } } // ] // ] + // //optional entry added later, datum_option = [ 0, $hash32 // 1, data ] + // //optional entry added later, script_ref = #6.24(bytes .cbor script) // ] { - BUILDER_APPEND_CBOR(CBOR_TYPE_MAP, 2 + output->includeDatumOption + output->includeScriptRef); - { - BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, output->addressSize); - BUILDER_APPEND_DATA(output->addressBuffer, output->addressSize); - } + BUILDER_APPEND_CBOR(CBOR_TYPE_ARRAY, 2); { - BUILDER_APPEND_CBOR(CBOR_TYPE_ARRAY, 2); - { - BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, output->amount); - BUILDER_APPEND_CBOR(CBOR_TYPE_MAP, output->numAssetGroups); - } + BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, output->amount); + BUILDER_APPEND_CBOR(CBOR_TYPE_MAP, output->numAssetGroups); } } builder->state = TX_HASH_BUILDER_IN_OUTPUTS_ASSET_GROUP; @@ -272,7 +273,7 @@ void txHashBuilder_init( if (includeTotalCollateral) numItems++; builder->remainingReferenceInputs = numReferenceInputs; - numItems++; // an array that is always included (even if empty) + if (numReferenceInputs > 0) numItems++; ASSERT((3 <= numItems) && (numItems <= 16)); @@ -326,6 +327,8 @@ static void txHashBuilder_assertCanLeaveInputs(tx_hash_builder_t* builder) ASSERT(builder->remainingInputs == 0); } +// ============================== OUTPUTS ============================== + void txHashBuilder_enterOutputs(tx_hash_builder_t* builder) { _TRACE("state = %d", builder->state); @@ -347,7 +350,19 @@ void txHashBuilder_addOutput_topLevelData( _TRACE("state = %d, remainingOutputs = %u", builder->state, builder->remainingOutputs); ASSERT(output->addressSize < BUFFER_SIZE_PARANOIA); - ASSERT(builder->state == TX_HASH_BUILDER_IN_OUTPUTS); + switch (builder->state) { + case TX_HASH_BUILDER_IN_OUTPUTS: + case TX_HASH_BUILDER_IN_OUTPUTS_ASSET_GROUP: + case TX_HASH_BUILDER_IN_OUTPUTS_TOP_LEVEL_DATA: + break; + //TODO move below to a seperate method + case TX_HASH_BUILDER_IN_OUTPUTS_SCRIPT_REFERENCE: + case TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION: + break; + + default: + ASSERT(false); + } ASSERT(builder->remainingOutputs > 0); builder->remainingOutputs--; @@ -420,8 +435,12 @@ static void addToken(tx_hash_builder_t* builder, } if (builder->multiassetData.remainingTokens == 0) { - builder->state = leaveState; // means we added all tokens for given group, so state should be either TX_HASH_BUILDER_IN_OUTPUTS_ASSET_GROUP or TX_HASH_BUILDER_IN_MINT_ASSET_GROUP + builder->state = nextGroupState; // means we added all tokens for given group, so state should be either TX_HASH_BUILDER_IN_OUTPUTS_ASSET_GROUP or TX_HASH_BUILDER_IN_MINT_ASSET_GROUP + if (builder->multiassetData.remainingAssetGroups == 0) { + builder->state = leaveState; // means we added all tokens for all groups, so state should be either TX_HASH_BUILDER_IN_OUTPUTS_TOP_LEVEL_DATA or TX_HASH_BUILDER_IN_MINT + } } + } void txHashBuilder_addOutput_tokenGroup( @@ -448,7 +467,7 @@ void txHashBuilder_addOutput_token( addToken(builder, assetNameBuffer, assetNameSize, amount, TX_HASH_BUILDER_IN_OUTPUTS_TOKEN, TX_HASH_BUILDER_IN_OUTPUTS_ASSET_GROUP, - TX_HASH_BUILDER_IN_OUTPUTS_ASSET_GROUP, + TX_HASH_BUILDER_IN_OUTPUTS_TOP_LEVEL_DATA, CBOR_TYPE_UNSIGNED); } @@ -486,50 +505,105 @@ void txHashBuilder_addOutput_datumHash( void txHashBuilder_addOutput_datumOption(tx_hash_builder_t *builder, datum_option_type_t datumOption, const uint8_t *buffer, size_t bufferSize) { - ASSERT(datumOption ? bufferSize < BUFFER_SIZE_PARANOIA : bufferSize == OUTPUT_DATUM_HASH_LENGTH); //?? + ASSERT(datumOption ? bufferSize < BUFFER_SIZE_PARANOIA : bufferSize == OUTPUT_DATUM_HASH_LENGTH); //TODO: MAX_DATUM_SIZE?? txHashBuilder_assertCanLeaveOutputTopLevelData(builder); // datum_option = [ 0, $hash32 // 1, data ] + + // Unsigned[0] ; entry key // Array(2)[ // Unsigned[0] // Bytes[buffer] // ] - + { + BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, TX_OUTPUT_KEY_DATUM_OPTION); + } BUILDER_APPEND_CBOR(CBOR_TYPE_ARRAY, 2); { BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, datumOption); } + if (datumOption == DATUM_OPTION_HASH) { + { + BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, bufferSize); + BUILDER_APPEND_DATA(buffer, bufferSize); + } + // Hash is transmitted in one chunk, and datumOption stage is finished + builder->state = TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION; + } else { + { + BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, bufferSize); + // Chunks of datum will be added later + } + // bufferSize is total size of datum + builder->totalDatumSize = bufferSize; + builder->currentDatumSize = 0; + + builder->state = TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION_CHUNKS; + } + +} + +void txHashBuilder_addOutput_datumOption_dataChunk(tx_hash_builder_t *builder, const uint8_t *buffer, + size_t bufferSize) +{ + ASSERT(builder->state == TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION_CHUNKS); { - BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, bufferSize); BUILDER_APPEND_DATA(buffer, bufferSize); } - builder->state = TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION; + builder->currentDatumSize += bufferSize; + + if(builder->totalDatumSize == builder->currentDatumSize) { + // transmission of data chunks has finished + builder->state = TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION; + } } -void txHashBuilder_addOutput_referenceScript(tx_hash_builder_t *builder, const uint8_t *scriptBuffer, size_t bufferSize) -{ - ASSERT(bufferSize < BUFFER_SIZE_PARANOIA); //?? - ASSERT(builder->state == TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION || builder->state == TX_HASH_BUILDER_IN_OUTPUTS_TOP_LEVEL_DATA); +void txHashBuilder_addOutput_referenceScript(tx_hash_builder_t *builder, size_t bufferSize) { + ASSERT(bufferSize < BUFFER_SIZE_PARANOIA); //TODO: MAX_SCRIPT_SIZE?? + ASSERT(builder->state == TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION || builder->state == TX_HASH_BUILDER_IN_OUTPUTS_TOP_LEVEL_DATA); + + // script_ref = #6.24(bytes .cbor script) - // script_ref = #6.24(bytes .cbor script) - // Bytes[buffer] + // Unsigned[0] ; entry key + // Bytes[buffer] + { + BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, TX_OUTPUT_KEY_SCRIPT_REF); + } + { + BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, bufferSize); + //Chunks will be added later + } + builder->totalReferenceScriptSize = bufferSize; + builder->currentReferenceScriptSize = 0; + builder->state = TX_HASH_BUILDER_IN_OUTPUTS_SCRIPT_REFERENCE_CHUNKS; +} +void txHashBuilder_addOutput_referenceScript_dataChunk(tx_hash_builder_t *builder, const uint8_t *buffer, + size_t bufferSize) +{ + ASSERT(builder->state == TX_HASH_BUILDER_IN_OUTPUTS_SCRIPT_REFERENCE_CHUNKS); { - BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, bufferSize); - BUILDER_APPEND_DATA(scriptBuffer, bufferSize); + BUILDER_APPEND_DATA(buffer, bufferSize); } -} + builder->currentReferenceScriptSize += bufferSize; + if(builder->totalReferenceScriptSize == builder->currentReferenceScriptSize) { + // transmission of data chunks has finished + builder->state = TX_HASH_BUILDER_IN_OUTPUTS_SCRIPT_REFERENCE; + } +} static void txHashBuilder_assertCanLeaveOutputs(tx_hash_builder_t* builder) { _TRACE("state = %d, remainingOutputs = %u", builder->state, builder->remainingOutputs); - ASSERT(builder->state == TX_HASH_BUILDER_IN_OUTPUTS); ASSERT(builder->remainingOutputs == 0); + txHashBuilder_assertCanLeaveOutputTopLevelData(builder); } +// ============================== FEE ============================== + void txHashBuilder_addFee(tx_hash_builder_t* builder, uint64_t fee) { _TRACE("state = %d", builder->state); @@ -581,6 +655,8 @@ static void txHashBuilder_assertCanLeaveTtl(tx_hash_builder_t* builder) } } +// ============================== CERTIFICATES ============================== + void txHashBuilder_enterCertificates(tx_hash_builder_t* builder) { _TRACE("state = %d, remaining certificates = %u", builder->state, builder->remainingCertificates); @@ -1156,6 +1232,8 @@ static void txHashBuilder_assertCanLeaveCertificates(tx_hash_builder_t* builder) ASSERT(builder->remainingCertificates == 0); } +// ============================== WITHDRAWALS ============================== + void txHashBuilder_enterWithdrawals(tx_hash_builder_t* builder) { _TRACE("state = %d, remainingWithdrawals = %u", builder->state, builder->remainingWithdrawals); @@ -1294,6 +1372,8 @@ static void txHashBuilder_assertCanLeaveValidityIntervalStart(tx_hash_builder_t* } } +// ============================== MINT ============================== + void txHashBuilder_enterMint(tx_hash_builder_t* builder) { _TRACE("state = %d", builder->state); @@ -1332,9 +1412,10 @@ void txHashBuilder_addMint_tokenGroup( ) { ASSERT(policyIdSize == MINTING_POLICY_ID_SIZE); + builder->state = TX_HASH_BUILDER_IN_MINT_ASSET_GROUP; - addTokenGroup(builder, policyIdBuffer, policyIdSize, numTokens, TX_HASH_BUILDER_IN_MINT_TOP_LEVEL_DATA, - TX_HASH_BUILDER_IN_MINT_TOKEN); + addTokenGroup(builder, policyIdBuffer, policyIdSize, numTokens, TX_HASH_BUILDER_IN_MINT_ASSET_GROUP, + TX_HASH_BUILDER_IN_MINT_ASSET_GROUP); } void txHashBuilder_addMint_token( @@ -1346,9 +1427,9 @@ void txHashBuilder_addMint_token( ASSERT(assetNameSize <= ASSET_NAME_SIZE_MAX); addToken(builder, assetNameBuffer, assetNameSize, amount, - TX_HASH_BUILDER_IN_MINT_TOKEN, TX_HASH_BUILDER_IN_MINT_ASSET_GROUP, TX_HASH_BUILDER_IN_MINT_TOKEN, + TX_HASH_BUILDER_IN_MINT, amount < 0 ? CBOR_TYPE_NEGATIVE : CBOR_TYPE_UNSIGNED); } @@ -1378,6 +1459,8 @@ static void txHashBuilder_assertCanLeaveMint(tx_hash_builder_t* builder) } } +// ========================= SCRIPT DATA HASH ========================== + void txHashBuilder_addScriptDataHash( tx_hash_builder_t* builder, const uint8_t* scriptHashData, size_t scriptHashDataSize diff --git a/src/txHashBuilder.h b/src/txHashBuilder.h index 8198e697..79022aad 100644 --- a/src/txHashBuilder.h +++ b/src/txHashBuilder.h @@ -24,6 +24,12 @@ enum { TX_BODY_KEY_REFERENCE_INPUTS = 18, //refInputs }; +enum { + TX_OUTPUT_KEY_ADDRESS = 1, + TX_OUTPUT_KEY_VALUE = 2, + TX_OUTPUT_KEY_DATUM_OPTION = 3, + TX_OUTPUT_KEY_SCRIPT_REF = 4, +}; /* The state machine of the tx hash builder is driven by user calls. * E.g., when the user calls txHashBuilder_addInput(), the input is only * added and the state is not advanced to outputs even if all inputs have been added @@ -43,7 +49,9 @@ typedef enum { TX_HASH_BUILDER_IN_OUTPUTS_TOKEN = 312, TX_HASH_BUILDER_IN_OUTPUTS_DATUM_HASH = 313, TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION = 314, - TX_HASH_BUILDER_IN_OUTPUTS_SCRIPT_REFERENCE = 315, + TX_HASH_BUILDER_IN_OUTPUTS_DATUM_OPTION_CHUNKS = 315, + TX_HASH_BUILDER_IN_OUTPUTS_SCRIPT_REFERENCE = 316, + TX_HASH_BUILDER_IN_OUTPUTS_SCRIPT_REFERENCE_CHUNKS = 317, TX_HASH_BUILDER_IN_FEE = 400, TX_HASH_BUILDER_IN_TTL = 500, TX_HASH_BUILDER_IN_CERTIFICATES = 600, @@ -80,6 +88,10 @@ typedef struct { uint16_t remainingCollaterals; uint16_t remainingRequiredSigners; uint16_t remainingReferenceInputs; + uint16_t totalDatumSize; + uint16_t currentDatumSize; + uint16_t totalReferenceScriptSize; + uint16_t currentReferenceScriptSize; bool includeTtl; bool includeAuxData; bool includeValidityIntervalStart; @@ -173,6 +185,8 @@ void txHashBuilder_addOutput_datumHash( void txHashBuilder_addOutput_datumOption(tx_hash_builder_t *builder, datum_option_type_t datumOption, const uint8_t *buffer, size_t bufferSize); +void txHashBuilder_addOutput_referenceScript(tx_hash_builder_t *builder, size_t bufferSize); + void txHashBuilder_addFee(tx_hash_builder_t* builder, uint64_t fee); void txHashBuilder_addTtl(tx_hash_builder_t* builder, uint64_t ttl); @@ -287,7 +301,8 @@ void txHashBuilder_addRequiredSigner( ); void txHashBuilder_addNetworkId(tx_hash_builder_t* builder, uint8_t networkId); - +void txHashBuilder_addCollateralReturn(tx_hash_builder_t *builder, + tx_hash_builder_output const *output); void txHashBuilder_addTotalCollateral(tx_hash_builder_t* builder, uint64_t txColl); void txHashBuilder_enterReferenceInputs(tx_hash_builder_t* builder); diff --git a/src/txHashBuilder_test.c b/src/txHashBuilder_test.c index 3bf2e77e..df97b320 100644 --- a/src/txHashBuilder_test.c +++ b/src/txHashBuilder_test.c @@ -166,12 +166,17 @@ static void addMultiassetOutput(tx_hash_builder_t* builder) { uint8_t tmp[70] = {0}; size_t tmpSize = decode_hex(PTR_PIC(outputs[1].rawAddressHex), tmp, SIZEOF(tmp)); + tx_hash_builder_output output; + output.format = LEGACY; + output.addressSize = tmpSize; + output.addressBuffer = tmp; + output.amount = outputs[1].amount; + output.numAssetGroups = 2; + output.includeDatumOption = false; + output.includeScriptRef = false; txHashBuilder_addOutput_topLevelData( builder, - tmp, tmpSize, - outputs[1].amount, - 2, - false + &output ); addTwoMultiassetTokenGroups(builder, &txHashBuilder_addOutput_tokenGroup, &outputTokenHandler); @@ -186,11 +191,17 @@ static void addOutputs(tx_hash_builder_t* builder) ITERATE(it, outputs) { uint8_t tmp[70] = {0}; size_t tmpSize = decode_hex(PTR_PIC(it->rawAddressHex), tmp, SIZEOF(tmp)); + tx_hash_builder_output output; + output.format = LEGACY; + output.addressSize = tmpSize; + output.addressBuffer = tmp; + output.amount = it->amount; + output.numAssetGroups = 0; + output.includeDatumOption = false; + output.includeScriptRef = false; txHashBuilder_addOutput_topLevelData( builder, - tmp, tmpSize, - it->amount, - 0, false + &output ); } @@ -376,7 +387,7 @@ void run_txHashBuilder_test() 0, // collaterals not tested yet 0, // required signers not tested yet false, // network id - true, // collateral return, + !true, // collateral return, true, // total collateral, ARRAY_LEN(inputs) // reference inputs not tested yet ); @@ -424,6 +435,8 @@ void run_txHashBuilder_test() addMint(&builder); +// txHashBuilder_addCollateralReturn(&builder,&output); + txHashBuilder_addTotalCollateral(&builder, 10); txHashBuilder_enterReferenceInputs(&builder);