From a733bbaae164f0ab7cabad469b9091abc3513cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Bruus=20Zeppelin?= Date: Mon, 13 Jan 2025 09:50:56 +0100 Subject: [PATCH 1/5] Added a static `1` to the energy cost calculation for all transactions --- packages/sdk/src/energyCost.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/src/energyCost.ts b/packages/sdk/src/energyCost.ts index 24190dfbe..460ffe60a 100644 --- a/packages/sdk/src/energyCost.ts +++ b/packages/sdk/src/energyCost.ts @@ -45,7 +45,7 @@ export function getEnergyCost( signatureCount = 1n ): Energy.Type { const handler = getAccountTransactionHandler(transactionType); - const size = handler.serialize(payload).length; + const size = handler.serialize(payload).length + 1; return calculateEnergyCost(signatureCount, BigInt(size), handler.getBaseEnergyCost(payload)); } From 9535eb8dba69e68fe094de167355a08407bbea8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Bruus=20Zeppelin?= Date: Mon, 13 Jan 2025 09:56:40 +0100 Subject: [PATCH 2/5] Version bump --- packages/sdk/CHANGELOG.md | 8 ++++++++ packages/sdk/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 621c3778c..263c30b0d 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Unreleased + +## 8.1.1 + +### Fixed + +- `getEnergyCost` returning energy amounts that were off by one compared to the amount calculated by the node. + ## 8.1.0 ### Added diff --git a/packages/sdk/package.json b/packages/sdk/package.json index f4892b4bb..0203c653e 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@concordium/web-sdk", - "version": "8.1.0", + "version": "8.1.1", "license": "Apache-2.0", "engines": { "node": ">=16" From 97cfa0c7e78a7b4bc0c6e064799c9730b8c46836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Bruus=20Zeppelin?= Date: Mon, 13 Jan 2025 10:12:49 +0100 Subject: [PATCH 3/5] Move missing transaction type size from nrg calculation into constant --- packages/sdk/src/energyCost.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/sdk/src/energyCost.ts b/packages/sdk/src/energyCost.ts index 460ffe60a..c820b402a 100644 --- a/packages/sdk/src/energyCost.ts +++ b/packages/sdk/src/energyCost.ts @@ -12,7 +12,10 @@ export const constantA = 100n; export const constantB = 1n; // Account address (32 bytes), nonce (8 bytes), energy (8 bytes), payload size (4 bytes), expiry (8 bytes); -const accountTransactionHeaderSize = BigInt(32 + 8 + 8 + 4 + 8); +const ACCOUNT_TRANSACTION_HEADER_SIZE = BigInt(32 + 8 + 8 + 4 + 8); + +/** Transaction type is defined by a UInt8, i.e 1 byte */ +const TRANSACTION_TYPE_SIZE = 1n; /** * The energy cost is assigned according to the formula: @@ -30,7 +33,9 @@ export function calculateEnergyCost( transactionSpecificCost: bigint ): Energy.Type { return Energy.create( - constantA * signatureCount + constantB * (accountTransactionHeaderSize + payloadSize) + transactionSpecificCost + constantA * signatureCount + + constantB * (TRANSACTION_TYPE_SIZE + ACCOUNT_TRANSACTION_HEADER_SIZE + payloadSize) + + transactionSpecificCost ); } @@ -45,7 +50,7 @@ export function getEnergyCost( signatureCount = 1n ): Energy.Type { const handler = getAccountTransactionHandler(transactionType); - const size = handler.serialize(payload).length + 1; + const size = handler.serialize(payload).length; return calculateEnergyCost(signatureCount, BigInt(size), handler.getBaseEnergyCost(payload)); } From 47d4ab8ba5021f69a91766e4608e345bc1bd4fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Bruus=20Zeppelin?= Date: Mon, 13 Jan 2025 11:57:05 +0100 Subject: [PATCH 4/5] Use `serializeAccountTransactionPayload` for serializing payloads, as this includes the transaction type. --- packages/sdk/CHANGELOG.md | 3 ++- packages/sdk/src/accountTransactions.ts | 2 ++ packages/sdk/src/energyCost.ts | 8 +++----- packages/sdk/src/serialization.ts | 17 +++++++---------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 263c30b0d..e130c98d9 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -6,7 +6,8 @@ ### Fixed -- `getEnergyCost` returning energy amounts that were off by one compared to the amount calculated by the node. +- `getEnergyCost` returning energy amounts that were off by one due to not including the transaction type in the + transaction payload serialization. ## 8.1.0 diff --git a/packages/sdk/src/accountTransactions.ts b/packages/sdk/src/accountTransactions.ts index 931b55654..becedab53 100644 --- a/packages/sdk/src/accountTransactions.ts +++ b/packages/sdk/src/accountTransactions.ts @@ -49,6 +49,8 @@ export interface AccountTransactionHandler< > { /** * Serializes the payload to a buffer. + * This does NOT include the serialized transaction type. To have this included, use {@linkcode serializeAccountTransactionPayload} instead. + * * @param payload - The payload to serialize. * @returns The serialized payload. */ diff --git a/packages/sdk/src/energyCost.ts b/packages/sdk/src/energyCost.ts index c820b402a..71fc3a64e 100644 --- a/packages/sdk/src/energyCost.ts +++ b/packages/sdk/src/energyCost.ts @@ -1,5 +1,6 @@ import { getAccountTransactionHandler } from './accountTransactions.js'; import { collapseRatio, multiplyRatio } from './ratioHelpers.js'; +import { serializeAccountTransactionPayload } from './serialization.ts'; import { AccountTransactionPayload, AccountTransactionType, ChainParameters, Ratio } from './types.js'; import * as CcdAmount from './types/CcdAmount.js'; import * as Energy from './types/Energy.js'; @@ -14,9 +15,6 @@ export const constantB = 1n; // Account address (32 bytes), nonce (8 bytes), energy (8 bytes), payload size (4 bytes), expiry (8 bytes); const ACCOUNT_TRANSACTION_HEADER_SIZE = BigInt(32 + 8 + 8 + 4 + 8); -/** Transaction type is defined by a UInt8, i.e 1 byte */ -const TRANSACTION_TYPE_SIZE = 1n; - /** * The energy cost is assigned according to the formula: * A * signatureCount + B * size + C_t, where C_t is a transaction specific cost. @@ -34,7 +32,7 @@ export function calculateEnergyCost( ): Energy.Type { return Energy.create( constantA * signatureCount + - constantB * (TRANSACTION_TYPE_SIZE + ACCOUNT_TRANSACTION_HEADER_SIZE + payloadSize) + + constantB * (ACCOUNT_TRANSACTION_HEADER_SIZE + payloadSize) + transactionSpecificCost ); } @@ -49,8 +47,8 @@ export function getEnergyCost( payload: AccountTransactionPayload, signatureCount = 1n ): Energy.Type { + const size = serializeAccountTransactionPayload({ payload, type: transactionType }).length; const handler = getAccountTransactionHandler(transactionType); - const size = handler.serialize(payload).length; return calculateEnergyCost(signatureCount, BigInt(size), handler.getBaseEnergyCost(payload)); } diff --git a/packages/sdk/src/serialization.ts b/packages/sdk/src/serialization.ts index 56cfc3be5..f91d62857 100644 --- a/packages/sdk/src/serialization.ts +++ b/packages/sdk/src/serialization.ts @@ -98,20 +98,18 @@ export function serializeAccountTransaction( const serializedBlockItemKind = encodeWord8(BlockItemKind.AccountTransactionKind); const serializedAccountTransactionSignatures = serializeAccountTransactionSignature(signatures); - const serializedType = serializeAccountTransactionType(accountTransaction.type); - const accountTransactionHandler = getAccountTransactionHandler(accountTransaction.type); - const serializedPayload = accountTransactionHandler.serialize(accountTransaction.payload); + const serializedPayload = serializeAccountTransactionPayload(accountTransaction); const baseEnergyCost = accountTransactionHandler.getBaseEnergyCost(accountTransaction.payload); const energyCost = calculateEnergyCost( countSignatures(signatures), - BigInt(serializedPayload.length + 1), + BigInt(serializedPayload.length), baseEnergyCost ); const serializedHeader = serializeAccountTransactionHeader( accountTransaction.header, - serializedPayload.length + 1, + serializedPayload.length, energyCost ); @@ -119,7 +117,6 @@ export function serializeAccountTransaction( serializedBlockItemKind, serializedAccountTransactionSignatures, serializedHeader, - serializedType, serializedPayload, ]); } @@ -129,7 +126,7 @@ export function serializeAccountTransaction( * @param accountTransaction the transaction which payload is to be serialized * @returns the account transaction payload serialized as a buffer. */ -export function serializeAccountTransactionPayload(accountTransaction: AccountTransaction): Buffer { +export function serializeAccountTransactionPayload(accountTransaction: Omit): Buffer { const serializedType = serializeAccountTransactionType(accountTransaction.type); const accountTransactionHandler = getAccountTransactionHandler(accountTransaction.type); @@ -160,13 +157,13 @@ export function getAccountTransactionHash( */ export function getAccountTransactionSignDigest(accountTransaction: AccountTransaction, signatureCount = 1n): Buffer { const accountTransactionHandler = getAccountTransactionHandler(accountTransaction.type); - const serializedPayload = accountTransactionHandler.serialize(accountTransaction.payload); + const serializedPayload = serializeAccountTransactionPayload(accountTransaction); const baseEnergyCost = accountTransactionHandler.getBaseEnergyCost(accountTransaction.payload); - const energyCost = calculateEnergyCost(signatureCount, BigInt(serializedPayload.length + 1), baseEnergyCost); + const energyCost = calculateEnergyCost(signatureCount, BigInt(serializedPayload.length), baseEnergyCost); const serializedHeader = serializeAccountTransactionHeader( accountTransaction.header, - serializedPayload.length + 1, + serializedPayload.length, energyCost ); From 24580eb769ce9981224f21e5641cf39001a84c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Bruus=20Zeppelin?= Date: Mon, 13 Jan 2025 12:16:35 +0100 Subject: [PATCH 5/5] fix failing build + test --- packages/sdk/src/energyCost.ts | 2 +- packages/sdk/src/serialization.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk/src/energyCost.ts b/packages/sdk/src/energyCost.ts index 71fc3a64e..71d72eb1e 100644 --- a/packages/sdk/src/energyCost.ts +++ b/packages/sdk/src/energyCost.ts @@ -1,6 +1,6 @@ import { getAccountTransactionHandler } from './accountTransactions.js'; import { collapseRatio, multiplyRatio } from './ratioHelpers.js'; -import { serializeAccountTransactionPayload } from './serialization.ts'; +import { serializeAccountTransactionPayload } from './serialization.js'; import { AccountTransactionPayload, AccountTransactionType, ChainParameters, Ratio } from './types.js'; import * as CcdAmount from './types/CcdAmount.js'; import * as Energy from './types/Energy.js'; diff --git a/packages/sdk/src/serialization.ts b/packages/sdk/src/serialization.ts index f91d62857..2b3051907 100644 --- a/packages/sdk/src/serialization.ts +++ b/packages/sdk/src/serialization.ts @@ -167,7 +167,7 @@ export function getAccountTransactionSignDigest(accountTransaction: AccountTrans energyCost ); - return sha256([serializedHeader, serializeAccountTransactionType(accountTransaction.type), serializedPayload]); + return sha256([serializedHeader, serializedPayload]); } /**