@@ -19,7 +19,7 @@ import { EthereumJSErrorWithoutCode } from './errors.ts'
1919import { assertIsBytes , assertIsHexString , assertIsString } from './helpers.ts'
2020import { stripHexPrefix } from './internal.ts'
2121
22- import type { BigIntLike , BytesLike , PrefixedHexString } from './types.ts'
22+ import type { BigIntLike , BytesLike , NestedUint8Array , PrefixedHexString } from './types.ts'
2323
2424export interface AccountData {
2525 nonce ?: BigIntLike
@@ -39,6 +39,35 @@ export interface PartialAccountData {
3939
4040export type AccountBodyBytes = [ Uint8Array , Uint8Array , Uint8Array , Uint8Array ]
4141
42+ /**
43+ * Handles the null indicator for RLP encoded accounts
44+ * @returns {null } is the null indicator is 0
45+ * @returns The unchanged value is the null indicator is 1
46+ * @throws if the null indicator is > 1
47+ * @throws if the length of values is < 2
48+ * @param value The value to convert
49+ * @returns The converted value
50+ */
51+ function handleNullIndicator ( values : NestedUint8Array | Uint8Array ) : Uint8Array | null {
52+ // Needed if some values are not provided to the array (e.g. partial account RLP)
53+ if ( values [ 0 ] === undefined ) {
54+ return null
55+ }
56+
57+ const nullIndicator = bytesToInt ( values [ 0 ] as Uint8Array )
58+
59+ if ( nullIndicator === 0 ) {
60+ return null
61+ }
62+ if ( nullIndicator > 1 ) {
63+ throw EthereumJSErrorWithoutCode ( `Invalid isNullIndicator=${ nullIndicator } ` )
64+ }
65+ if ( values . length < 2 ) {
66+ throw EthereumJSErrorWithoutCode ( `Invalid values length=${ values . length } ` )
67+ }
68+ return values [ 1 ] as Uint8Array
69+ }
70+
4271/**
4372 * Account class to load and maintain the basic account objects.
4473 * Supports partial loading and access required for verkle with null
@@ -126,8 +155,10 @@ export class Account {
126155
127156 /**
128157 * This constructor assigns and validates the values.
129- * Use the static factory methods to assist in creating an Account from varying data types.
130- * undefined get assigned with the defaults present, but null args are retained as is
158+ * It is not recommended to use this constructor directly. Instead use the static
159+ * factory methods to assist in creating an Account from varying data types.
160+ * undefined get assigned with the defaults, but null args are retained as is
161+ * @deprecated
131162 */
132163 constructor (
133164 nonce : bigint | null = BIGINT_0 ,
@@ -325,91 +356,26 @@ export function createAccountFromRLP(serialized: Uint8Array) {
325356}
326357
327358export function createPartialAccountFromRLP ( serialized : Uint8Array ) {
328- const values = RLP . decode ( serialized ) as Uint8Array [ ] [ ]
359+ const values = RLP . decode ( serialized )
329360
330361 if ( ! Array . isArray ( values ) ) {
331362 throw EthereumJSErrorWithoutCode ( 'Invalid serialized account input. Must be array' )
332363 }
333364
334- let nonce = null
335- if ( ! Array . isArray ( values [ 0 ] ) ) {
336- throw EthereumJSErrorWithoutCode ( 'Invalid partial nonce encoding. Must be array' )
337- } else {
338- const isNotNullIndicator = bytesToInt ( values [ 0 ] [ 0 ] )
339- if ( isNotNullIndicator !== 0 && isNotNullIndicator !== 1 ) {
340- throw EthereumJSErrorWithoutCode ( `Invalid isNullIndicator=${ isNotNullIndicator } for nonce` )
341- }
342- if ( isNotNullIndicator === 1 ) {
343- nonce = bytesToBigInt ( values [ 0 ] [ 1 ] )
365+ for ( const value of values ) {
366+ // Ensure that each array item is an array
367+ if ( ! Array . isArray ( value ) ) {
368+ throw EthereumJSErrorWithoutCode ( 'Invalid partial encoding. Each item must be an array' )
344369 }
345370 }
346371
347- let balance = null
348- if ( ! Array . isArray ( values [ 1 ] ) ) {
349- throw EthereumJSErrorWithoutCode ( 'Invalid partial balance encoding. Must be array' )
350- } else {
351- const isNotNullIndicator = bytesToInt ( values [ 1 ] [ 0 ] )
352- if ( isNotNullIndicator !== 0 && isNotNullIndicator !== 1 ) {
353- throw EthereumJSErrorWithoutCode ( `Invalid isNullIndicator=${ isNotNullIndicator } for balance` )
354- }
355- if ( isNotNullIndicator === 1 ) {
356- balance = bytesToBigInt ( values [ 1 ] [ 1 ] )
357- }
358- }
372+ const [ nonceRaw , balanceRaw , storageRoot , codeHash , codeSizeRaw , versionRaw ] =
373+ values . map ( handleNullIndicator )
359374
360- let storageRoot = null
361- if ( ! Array . isArray ( values [ 2 ] ) ) {
362- throw EthereumJSErrorWithoutCode ( 'Invalid partial storageRoot encoding. Must be array' )
363- } else {
364- const isNotNullIndicator = bytesToInt ( values [ 2 ] [ 0 ] )
365- if ( isNotNullIndicator !== 0 && isNotNullIndicator !== 1 ) {
366- throw EthereumJSErrorWithoutCode (
367- `Invalid isNullIndicator=${ isNotNullIndicator } for storageRoot` ,
368- )
369- }
370- if ( isNotNullIndicator === 1 ) {
371- storageRoot = values [ 2 ] [ 1 ]
372- }
373- }
374-
375- let codeHash = null
376- if ( ! Array . isArray ( values [ 3 ] ) ) {
377- throw EthereumJSErrorWithoutCode ( 'Invalid partial codeHash encoding. Must be array' )
378- } else {
379- const isNotNullIndicator = bytesToInt ( values [ 3 ] [ 0 ] )
380- if ( isNotNullIndicator !== 0 && isNotNullIndicator !== 1 ) {
381- throw EthereumJSErrorWithoutCode ( `Invalid isNullIndicator=${ isNotNullIndicator } for codeHash` )
382- }
383- if ( isNotNullIndicator === 1 ) {
384- codeHash = values [ 3 ] [ 1 ]
385- }
386- }
387-
388- let codeSize = null
389- if ( ! Array . isArray ( values [ 4 ] ) ) {
390- throw EthereumJSErrorWithoutCode ( 'Invalid partial codeSize encoding. Must be array' )
391- } else {
392- const isNotNullIndicator = bytesToInt ( values [ 4 ] [ 0 ] )
393- if ( isNotNullIndicator !== 0 && isNotNullIndicator !== 1 ) {
394- throw EthereumJSErrorWithoutCode ( `Invalid isNullIndicator=${ isNotNullIndicator } for codeSize` )
395- }
396- if ( isNotNullIndicator === 1 ) {
397- codeSize = bytesToInt ( values [ 4 ] [ 1 ] )
398- }
399- }
400-
401- let version = null
402- if ( ! Array . isArray ( values [ 5 ] ) ) {
403- throw EthereumJSErrorWithoutCode ( 'Invalid partial version encoding. Must be array' )
404- } else {
405- const isNotNullIndicator = bytesToInt ( values [ 5 ] [ 0 ] )
406- if ( isNotNullIndicator !== 0 && isNotNullIndicator !== 1 ) {
407- throw EthereumJSErrorWithoutCode ( `Invalid isNullIndicator=${ isNotNullIndicator } for version` )
408- }
409- if ( isNotNullIndicator === 1 ) {
410- version = bytesToInt ( values [ 5 ] [ 1 ] )
411- }
412- }
375+ const nonce = nonceRaw === null ? null : bytesToBigInt ( nonceRaw )
376+ const balance = balanceRaw === null ? null : bytesToBigInt ( balanceRaw )
377+ const codeSize = codeSizeRaw === null ? null : bytesToInt ( codeSizeRaw )
378+ const version = versionRaw === null ? null : bytesToInt ( versionRaw )
413379
414380 return createPartialAccount ( { balance, nonce, storageRoot, codeHash, codeSize, version } )
415381}
0 commit comments