Skip to content

Commit 6a3be47

Browse files
committed
fix: wrong capacity completion while deserializing transaction
1 parent 28c6673 commit 6a3be47

File tree

5 files changed

+78
-24
lines changed

5 files changed

+78
-24
lines changed

.changeset/purple-states-judge.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@ckb-ccc/core": patch
3+
---
4+
5+
fix: wrong capacity completion while deserializing transaction
6+

packages/core/src/ckb/transaction.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,15 @@ describe("Transaction", () => {
656656
expect(cellOutput.capacity).toBe(1000n);
657657
});
658658

659+
it("should not modify capacity when data is not provided", () => {
660+
const cellOutput = ccc.CellOutput.from({
661+
capacity: 0n,
662+
lock,
663+
});
664+
665+
expect(cellOutput.capacity).toBe(0n);
666+
});
667+
659668
it("should calculate capacity automatically when capacity is 0", () => {
660669
const outputData = "0x1234"; // 2 bytes
661670
const cellOutput = ccc.CellOutput.from(
@@ -813,6 +822,30 @@ describe("Transaction", () => {
813822
);
814823
});
815824

825+
it("should automatically fill capacity considering outputData while deserialization", () => {
826+
const outputsData = ["0x1234"];
827+
const calculatedTx = ccc.Transaction.from({
828+
outputs: [
829+
{
830+
lock,
831+
},
832+
],
833+
outputsData,
834+
});
835+
calculatedTx.outputs[0].capacity = 0n;
836+
const data = calculatedTx.toBytes();
837+
expect(ccc.hexFrom(data)).toBe(
838+
"0xb30000000c000000af000000a30000001c0000002000000024000000280000002c00000095000000000000000000000000000000000000006900000008000000610000001000000018000000610000000000000000000000490000001000000030000000310000009bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8011400000036053c1bbc237e164137c03664fe8384b2cf9b260e0000000800000002000000123404000000",
839+
);
840+
const tx = ccc.Transaction.fromBytes(data);
841+
842+
// Should use outputData for calculation
843+
const expectedCapacity = 8 + lock.occupiedSize + 2;
844+
expect(tx.outputs[0].capacity).toBe(
845+
ccc.fixedPointFrom(expectedCapacity),
846+
);
847+
});
848+
816849
it("should handle empty outputsData array", () => {
817850
const tx = ccc.Transaction.from({
818851
outputs: [

packages/core/src/ckb/transaction.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export class CellOutput extends mol.Entity.Base<CellOutputLike, CellOutput>() {
235235

236236
/**
237237
* Creates a CellOutput instance from a CellOutputLike object.
238-
* This method supports automatic capacity calculation when capacity is 0 or omitted.
238+
* This method supports automatic capacity calculation when outputData is provided and capacity is 0 or omitted.
239239
*
240240
* @param cellOutput - A CellOutputLike object or an instance of CellOutput.
241241
* @param outputData - Optional output data used for automatic capacity calculation.
@@ -262,19 +262,20 @@ export class CellOutput extends mol.Entity.Base<CellOutputLike, CellOutput>() {
262262
cellOutput: CellOutputLike,
263263
outputData?: HexLike | null,
264264
): CellOutput {
265-
if (cellOutput instanceof CellOutput) {
266-
return cellOutput;
267-
}
268-
269-
const output = new CellOutput(
270-
numFrom(cellOutput.capacity ?? 0),
271-
Script.from(cellOutput.lock),
272-
apply(Script.from, cellOutput.type),
273-
);
265+
const output = (() => {
266+
if (cellOutput instanceof CellOutput) {
267+
return cellOutput;
268+
}
269+
return new CellOutput(
270+
numFrom(cellOutput.capacity ?? 0),
271+
Script.from(cellOutput.lock),
272+
apply(Script.from, cellOutput.type),
273+
);
274+
})();
274275

275-
if (output.capacity === Zero) {
276+
if (output.capacity === Zero && outputData != null) {
276277
output.capacity = fixedPointFrom(
277-
output.occupiedSize + bytesFrom(outputData ?? "0x").length,
278+
output.occupiedSize + bytesFrom(outputData).length,
278279
);
279280
}
280281

@@ -365,9 +366,11 @@ export class CellAny {
365366
return cell;
366367
}
367368

369+
const outputData = hexFrom(cell.outputData ?? "0x");
370+
368371
return new CellAny(
369-
CellOutput.from(cell.cellOutput, cell.outputData),
370-
hexFrom(cell.outputData ?? "0x"),
372+
CellOutput.from(cell.cellOutput, outputData),
373+
outputData,
371374
apply(OutPoint.from, cell.outPoint ?? cell.previousOutput),
372375
);
373376
}

packages/core/src/molecule/entity.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ export abstract class Entity {
128128
}
129129
}
130130

131+
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment */
132+
Impl.encode = undefined as any;
133+
Impl.decode = undefined as any;
134+
Impl.fromBytes = undefined as any;
135+
/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment */
136+
131137
return Impl;
132138
}
133139

@@ -168,15 +174,21 @@ export function codec<
168174
},
169175
>(Constructor: ConstructorType, ..._: unknown[]) {
170176
Constructor.byteLength = codec.byteLength;
171-
Constructor.encode = function (encodable: TypeLike) {
172-
return codec.encode(encodable);
173-
};
174-
Constructor.decode = function (bytesLike: BytesLike) {
175-
return Constructor.from(codec.decode(bytesLike));
176-
};
177-
Constructor.fromBytes = function (bytes: BytesLike) {
178-
return Constructor.from(codec.decode(bytes));
179-
};
177+
if (Constructor.encode === undefined) {
178+
Constructor.encode = function (encodable: TypeLike) {
179+
return codec.encode(encodable);
180+
};
181+
}
182+
if (Constructor.decode === undefined) {
183+
Constructor.decode = function (bytesLike: BytesLike) {
184+
return Constructor.from(codec.decode(bytesLike));
185+
};
186+
}
187+
if (Constructor.fromBytes === undefined) {
188+
Constructor.fromBytes = function (bytes: BytesLike) {
189+
return Constructor.from(codec.decode(bytes));
190+
};
191+
}
180192

181193
return Constructor;
182194
};

packages/playground/src/app/components/Cell.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export function Cell({
176176
return 0;
177177
}
178178

179-
const total = cellOutput.capacity;
179+
const total = ccc.numMax(cellOutput.capacity, 1);
180180
const freeSize =
181181
total -
182182
ccc.fixedPointFrom(

0 commit comments

Comments
 (0)