decodeBchRawTx function
Hardened reader for the legacy (non-witness) transaction serialization.
Implementation
DecodedBchTx decodeBchRawTx(String rawTxHex) {
Uint8List bytes;
try {
bytes = hexToBytes(rawTxHex);
} on Object {
throw EraSdkError('malformed-reply', 'signed transaction is not hex');
}
var offset = 0;
void need(int n) {
if (offset + n > bytes.length) {
throw EraSdkError('malformed-reply', 'signed transaction is truncated');
}
}
int readU32() {
need(4);
final v = bytes[offset] |
(bytes[offset + 1] << 8) |
(bytes[offset + 2] << 16) |
(bytes[offset + 3] << 24);
offset += 4;
return v;
}
BigInt readU64() {
need(8);
var v = BigInt.zero;
for (var i = 7; i >= 0; i--) {
v = (v << 8) | BigInt.from(bytes[offset + i]);
}
offset += 8;
return v;
}
int readVarint() {
need(1);
final first = bytes[offset++];
if (first < 0xfd) return first;
if (first == 0xfd) {
need(2);
final v = bytes[offset] | (bytes[offset + 1] << 8);
offset += 2;
return v;
}
// 4- and 8-byte counts cannot occur in a transaction the device can build.
throw EraSdkError(
'malformed-reply',
'unreasonable varint in signed transaction',
);
}
Uint8List readSlice(int n) {
need(n);
final s = Uint8List.sublistView(bytes, offset, offset + n);
offset += n;
return s;
}
final version = readU32();
final inputCount = readVarint();
if (inputCount == 0 || inputCount > 1000) {
throw EraSdkError(
'malformed-reply',
'unreasonable input count in signed transaction',
);
}
final inputs = <DecodedBchInput>[];
for (var i = 0; i < inputCount; i++) {
final txidLE = readSlice(32);
final index = readU32();
final scriptSig = readSlice(readVarint());
final sequence = readU32();
inputs.add(DecodedBchInput(
txidLE: txidLE,
index: index,
scriptSig: scriptSig,
sequence: sequence,
));
}
final outputCount = readVarint();
if (outputCount == 0 || outputCount > 1000) {
throw EraSdkError(
'malformed-reply',
'unreasonable output count in signed transaction',
);
}
final outputs = <DecodedBchOutput>[];
for (var i = 0; i < outputCount; i++) {
final value = readU64();
final script = readSlice(readVarint());
outputs.add(DecodedBchOutput(value: value, script: script));
}
final locktime = readU32();
if (offset != bytes.length) {
throw EraSdkError(
'malformed-reply',
'trailing bytes after signed transaction',
);
}
return DecodedBchTx(
version: version,
inputs: inputs,
outputs: outputs,
locktime: locktime,
);
}