diff --git a/lib/src/crypto/evm/utils/rlp.dart b/lib/src/crypto/evm/utils/rlp.dart index 1580a6b39..67761343a 100644 --- a/lib/src/crypto/evm/utils/rlp.dart +++ b/lib/src/crypto/evm/utils/rlp.dart @@ -3,6 +3,10 @@ import 'dart:typed_data'; import 'package:walletkit_dart/src/domain/extensions.dart'; +/// Whether to strictly enforce RLP decoding rules. +/// We recommned leaving this enabled unless you have a specific reason to disable it. +bool STRICT_RLP_DECODE = true; + final class RLPException implements Exception { final String message; const RLPException(this.message); @@ -278,7 +282,7 @@ RLPItem decodeRLPCheck(Uint8List input) { offset + 1, offset + 1 + length, ); - if (offset == 0 && length == 1 && result[0] < 0x80) { + if (STRICT_RLP_DECODE && length == 1 && result[0] < 0x80) { throw RLPException( "invalid RLP encoding: invalid prefix, single byte < 0x80 are not prefixed", ); diff --git a/test/ci/evm/parsing/parse_hex_transaction_test.dart b/test/ci/evm/parsing/parse_hex_transaction_test.dart index 1c799646c..9b9df3a96 100644 --- a/test/ci/evm/parsing/parse_hex_transaction_test.dart +++ b/test/ci/evm/parsing/parse_hex_transaction_test.dart @@ -41,9 +41,19 @@ void main() { }); test('Parse hex string to RawEvmTransaction', () { + STRICT_RLP_DECODE = true; const msgHex = "f86b8151843b9aca00830124f894e9e7CEA3DedcA5984780Bafc599bD69ADd087D5680b844a9059cbb000000000000000000000000a7fa4bb0bba164f999e8c7b83c9da96a3be44616000000000000000000000000000000000000000000000000000000000000271081388080"; + expect( + () => RawEvmTransaction.fromUnsignedHex(msgHex), + throwsA( + isA(), + ), + ); + + STRICT_RLP_DECODE = false; + final tx = RawEvmTransaction.fromUnsignedHex(msgHex); expect(tx.nonce, BigInt.from(81)); diff --git a/test/ci/rlp/rlp_test.dart b/test/ci/rlp/rlp_test.dart index 436a5edc1..b032605d8 100644 --- a/test/ci/rlp/rlp_test.dart +++ b/test/ci/rlp/rlp_test.dart @@ -353,23 +353,23 @@ void main() { }); }); - // group('Invalid encodings', () { - // test('should reject invalid RLP encodings', () { - // final invalidCases = [ - // // Invalid length prefix - // 'f86081000182520894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3', - // // Extra data at end: Is actually a valid RLP. The extra data is just an empty List. - // // 'f90260f901f9a02a3c692012a15502ba9c39f3aebb36694eed978c74b52e6c0cf210d301dbf325a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0b6c9fd1447d0b414a1f05957927746f58ef5a2ebde17db631d460eaf6a93b18da0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845509814280a00451dd53d9c09f3cfb627b51d9d80632ed801f6330ee584bffc26caac9b9249f88c7bffe5ebd94cc2ff861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba098c3a099885a281885f487fd37550de16436e8c47874cd213531b10fe751617fa044b6b81011ce57bffcaf610bf728fb8a7237ad261ea2d937423d78eb9e137076c0', - // ]; - - // for (final hexInput in invalidCases) { - // expect( - // () => decodeRLPCheck((hexInput.hexToBytes)), - // throwsA(isA()), - // ); - // } - // }); - // }); + group('Invalid encodings', () { + test('should reject invalid RLP encodings', () { + final invalidCases = [ + // Invalid length prefix + 'f86081000182520894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3', + // Extra data at end: Is actually a valid RLP. The extra data is just an empty List. + // 'f90260f901f9a02a3c692012a15502ba9c39f3aebb36694eed978c74b52e6c0cf210d301dbf325a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0b6c9fd1447d0b414a1f05957927746f58ef5a2ebde17db631d460eaf6a93b18da0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845509814280a00451dd53d9c09f3cfb627b51d9d80632ed801f6330ee584bffc26caac9b9249f88c7bffe5ebd94cc2ff861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba098c3a099885a281885f487fd37550de16436e8c47874cd213531b10fe751617fa044b6b81011ce57bffcaf610bf728fb8a7237ad261ea2d937423d78eb9e137076c0', + ]; + + for (final hexInput in invalidCases) { + expect( + () => decodeRLPCheck((hexInput.hexToBytes)), + throwsA(isA()), + ); + } + }); + }); group('Leading zeros', () { test('should correctly encode single byte with leading zeros', () {