-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
added support for txn >5kB #51
base: main
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -62,52 +62,50 @@ export const signTxn = async ( | |||||
meta: { | ||||||
version: signTxnDefaultParams.version, | ||||||
locktime: params.txn.locktime ?? signTxnDefaultParams.locktime, | ||||||
inputSize: params.txn.inputs.length, | ||||||
outputSize: params.txn.inputs.length, | ||||||
hashType: params.txn.hashType ?? signTxnDefaultParams.hashtype, | ||||||
inputCount: params.txn.inputs.length, | ||||||
outputCount: params.txn.outputs.length, | ||||||
sighash: params.txn.hashType ?? signTxnDefaultParams.hashtype, | ||||||
}, | ||||||
}); | ||||||
const { metaAccepted } = await helper.waitForResult(); | ||||||
assertOrThrowInvalidResult(metaAccepted); | ||||||
|
||||||
for (let i = 0; i < params.txn.inputs.length; i += 1) { | ||||||
const { input: inputRequest } = await helper.waitForResult(); | ||||||
assertOrThrowInvalidResult(inputRequest); | ||||||
assertOrThrowInvalidResult(inputRequest.index === i); | ||||||
|
||||||
const input = params.txn.inputs[i]; | ||||||
await helper.sendQuery({ | ||||||
input: { | ||||||
prevTxn: hexToUint8Array(input.prevTxn), | ||||||
prevTxnHash: hexToUint8Array(input.prevTxnHash), | ||||||
prevIndex: input.prevIndex, | ||||||
prevOutputIndex: input.prevIndex, | ||||||
scriptPubKey: hexToUint8Array(input.scriptPubKey), | ||||||
value: input.value, | ||||||
sequence: input.sequence ?? signTxnDefaultParams.input.sequence, | ||||||
chainIndex: input.chainIndex, | ||||||
changeIndex: input.chainIndex, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename the params to
Suggested change
|
||||||
addressIndex: input.addressIndex, | ||||||
}, | ||||||
}); | ||||||
const { inputAccepted } = await helper.waitForResult(); | ||||||
assertOrThrowInvalidResult(inputAccepted); | ||||||
} | ||||||
|
||||||
for (let i = 0; i < params.txn.outputs.length; i += 1) { | ||||||
const { output: outputRequest } = await helper.waitForResult(); | ||||||
assertOrThrowInvalidResult(outputRequest); | ||||||
assertOrThrowInvalidResult(outputRequest.index === i); | ||||||
for (let i = 0; i < params.txn.rawTxn.length; i += 1) { | ||||||
const txnBytes = hexToUint8Array(params.txn.rawTxn[i]); | ||||||
await helper.sendInChunks(txnBytes, 'rawTxn', 'rawTxn'); | ||||||
} | ||||||
|
||||||
for (let i = 0; i < params.txn.outputs.length; i += 1) { | ||||||
const output = params.txn.outputs[i]; | ||||||
await helper.sendQuery({ | ||||||
output: { | ||||||
scriptPubKey: hexToUint8Array(output.scriptPubKey), | ||||||
value: output.value, | ||||||
isChange: output.isChange, | ||||||
chainIndex: output.chainIndex, | ||||||
addressIndex: output.addressIndex, | ||||||
changesIndex: output.chainIndex, | ||||||
}, | ||||||
}); | ||||||
const { outputAccepted } = await helper.waitForResult(); | ||||||
assertOrThrowInvalidResult(outputAccepted); | ||||||
} | ||||||
|
||||||
const { verified } = await helper.waitForResult(); | ||||||
assertOrThrowInvalidResult(verified); | ||||||
|
||||||
forceStatusUpdate(SignTxnStatus.SIGN_TXN_STATUS_VERIFY); | ||||||
|
||||||
const signatures: string[] = []; | ||||||
|
@@ -122,7 +120,7 @@ export const signTxn = async ( | |||||
const { signature } = await helper.waitForResult(); | ||||||
assertOrThrowInvalidResult(signature); | ||||||
|
||||||
signatures.push(uint8ArrayToHex(signature.signature)); | ||||||
signatures.push(uint8ArrayToHex(signature.unlockingScript)); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return the signedTxn as well, check eth sign txn |
||||||
} | ||||||
|
||||||
forceStatusUpdate(SignTxnStatus.SIGN_TXN_STATUS_CARD); | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,20 +2,18 @@ import { SignTxnStatus } from '../../proto/generated/types'; | |
|
||
export type SignTxnEventHandler = (event: SignTxnStatus) => void; | ||
|
||
export interface ISignTxnInput { | ||
export interface ISignTxnInputData { | ||
prevTxnHash: string; | ||
prevIndex: number; | ||
value: string; | ||
scriptPubKey: string; | ||
|
||
chainIndex: number; | ||
addressIndex: number; | ||
|
||
prevTxn: string; | ||
sequence?: number; | ||
} | ||
|
||
export interface ISignTxnOutput { | ||
export interface ISignTxnOutputData { | ||
value: string; | ||
scriptPubKey: string; | ||
|
||
|
@@ -30,8 +28,9 @@ export interface ISignTxnParams { | |
onEvent?: SignTxnEventHandler; | ||
|
||
txn: { | ||
inputs: ISignTxnInput[]; | ||
outputs: ISignTxnOutput[]; | ||
inputs: ISignTxnInputData[]; | ||
outputs: ISignTxnOutputData[]; | ||
rawTxn: string[]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can make this optional and fetch it from server when it's not provided. |
||
locktime?: number; | ||
hashType?: number; | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ import { DeviceAppError, DeviceAppErrorType } from '@cypherock/sdk-interfaces'; | |
import { OnStatus } from '@cypherock/sdk-utils'; | ||
import { DeepPartial, Exact, Query, Result } from '../proto/generated/btc/core'; | ||
import { assertOrThrowInvalidResult, parseCommonError } from './asserts'; | ||
import { ChunkAck, ChunkPayload } from '../proto/generated/common'; | ||
|
||
export function decodeResult(data: Uint8Array) { | ||
let result: Result; | ||
|
@@ -33,6 +34,8 @@ export class OperationHelper<Q extends QueryKey, R extends ResultKey> { | |
|
||
private readonly onStatus?: OnStatus; | ||
|
||
private static readonly CHUNK_SIZE = 5120; | ||
|
||
constructor(params: { | ||
sdk: ISDK; | ||
queryKey: Q; | ||
|
@@ -63,4 +66,57 @@ export class OperationHelper<Q extends QueryKey, R extends ResultKey> { | |
parseCommonError((result[this.resultKey] as any).commonError); | ||
return resultData; | ||
} | ||
|
||
private static splitIntoChunks(txn: Uint8Array): Uint8Array[] { | ||
const chunks: Uint8Array[] = []; | ||
const totalChunks = Math.ceil(txn.length / OperationHelper.CHUNK_SIZE); | ||
|
||
for (let i = 0; i < totalChunks; i += 1) { | ||
const chunk = txn.slice( | ||
i * OperationHelper.CHUNK_SIZE, | ||
i * OperationHelper.CHUNK_SIZE + OperationHelper.CHUNK_SIZE, | ||
); | ||
chunks.push(chunk); | ||
} | ||
|
||
return chunks; | ||
} | ||
|
||
public async sendInChunks< | ||
RK extends keyof Exclude<Result[R], null | undefined>, | ||
QK extends keyof Exclude<Query[Q], null | undefined>, | ||
>(data: Uint8Array, queryKey: QK, resultKey: RK) { | ||
const chunks = OperationHelper.splitIntoChunks(data); | ||
let remainingSize = data.length; | ||
|
||
for (let i = 0; i < chunks.length; i += 1) { | ||
const chunk = chunks[i]; | ||
remainingSize -= chunk.length; | ||
Comment on lines
+69
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need to send in chunks in this PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that was part of latest proto, it's split between 2 commits, this commit There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can open another pr from just that commit if we need to skip chink changes. |
||
|
||
const chunkPayload: ChunkPayload = { | ||
chunk, | ||
chunkIndex: i, | ||
totalChunks: chunks.length, | ||
remainingSize, | ||
}; | ||
|
||
await this.sendQuery({ | ||
[queryKey]: { | ||
chunkPayload, | ||
}, | ||
}); | ||
|
||
const result = await this.waitForResult(); | ||
assertOrThrowInvalidResult(result[resultKey]); | ||
|
||
const { chunkAck } = result[resultKey] as { | ||
chunkAck: ChunkAck; | ||
}; | ||
|
||
assertOrThrowInvalidResult(chunkAck); | ||
assertOrThrowInvalidResult( | ||
chunkPayload.chunkIndex === chunkAck.chunkIndex, | ||
); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ const commonParams = { | |
sequence: 0xffffffff, | ||
}, | ||
], | ||
rawTxn: ['0000'], | ||
outputs: [ | ||
{ | ||
value: '3547271', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ const validParams = { | |
sequence: 0xffffffff, | ||
}, | ||
], | ||
rawTxn: ['0000'], | ||
outputs: [ | ||
{ | ||
value: '3547271', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ const commonParams = { | |
sequence: 0xffffffff, | ||
}, | ||
], | ||
rawTxn: ['0000'], | ||
outputs: [ | ||
{ | ||
value: '3547271', | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The assert and the error message is conflicting