@@ -185,7 +185,7 @@ class TinyChainInstance {
185185 * @returns {boolean } `true` if a valid genesis block is present, otherwise `false`.
186186 */
187187 hasGenesisBlock ( ) {
188- if ( this . chain . length === 0 ) return false ;
188+ if ( this . #getChain ( ) . length === 0 ) return false ;
189189 const firstBlock = this . getFirstBlock ( ) ;
190190 return (
191191 firstBlock . index === 0n &&
@@ -209,6 +209,32 @@ class TinyChainInstance {
209209 */
210210 initialBalances = { } ;
211211
212+ /**
213+ * Validates and returns the internal balances object.
214+ * Throws an error if balances is not a plain object.
215+ *
216+ * @returns {Balances } A reference to the balances object if valid.
217+ * @throws {Error } If balances is not a plain object.
218+ */
219+ #getBalances( ) {
220+ if ( typeof this . balances !== 'object' || this . balances === null || Array . isArray ( this . balances ) )
221+ throw new Error ( 'balances must be a plain object' ) ;
222+ return this . balances ;
223+ }
224+
225+ /**
226+ * Safely retrieves the current blockchain array.
227+ * Ensures that `this.chain` is a valid array before returning it.
228+ * If the internal `chain` property is corrupted or invalid, an error is thrown to prevent further logic failures.
229+ *
230+ * @returns {TinyChainBlock[] } The current blockchain as an array of TinyChainBlock instances.
231+ * @throws {Error } If `this.chain` is not an array.
232+ */
233+ #getChain( ) {
234+ if ( ! Array . isArray ( this . chain ) ) throw new Error ( 'chain must be an array' ) ;
235+ return this . chain ;
236+ }
237+
212238 /**
213239 * Constructs a new blockchain instance with optional configuration parameters.
214240 *
@@ -478,8 +504,8 @@ class TinyChainInstance {
478504 *
479505 */
480506 #init( signer = this . #signer) {
481- if ( this . chain . length > 0 )
482- throw new Error ( 'Blockchain already initialized with a genesis block' ) ;
507+ const chain = this . #getChain ( ) ;
508+ if ( chain . length > 0 ) throw new Error ( 'Blockchain already initialized with a genesis block' ) ;
483509
484510 const data = {
485511 transfers : [ ] ,
@@ -502,7 +528,7 @@ class TinyChainInstance {
502528 data : [ data ] ,
503529 sigs : [ sig . toString ( 'hex' ) ] ,
504530 } ) ;
505- this . chain . push ( block ) ;
531+ chain . push ( block ) ;
506532 return block ;
507533 }
508534
@@ -622,11 +648,12 @@ class TinyChainInstance {
622648 * @returns {boolean|null } Returns `true` if the chain is valid, `false` or `null` otherwise.
623649 */
624650 isValid ( startIndex = 0 , endIndex = null ) {
625- const end = endIndex ?? this . chain . length - 1 ;
651+ const chain = this . #getChain( ) ;
652+ const end = endIndex ?? chain . length - 1 ;
626653
627654 for ( let i = Math . max ( startIndex , 1 ) ; i <= end ; i ++ ) {
628- const current = this . chain [ i ] ;
629- const previous = this . chain [ i - 1 ] ;
655+ const current = chain [ i ] ;
656+ const previous = chain [ i - 1 ] ;
630657 const result = this . #isValidBlock( current , previous ) ;
631658 if ( ! result ) return result ;
632659 }
@@ -768,7 +795,7 @@ class TinyChainInstance {
768795 if ( ! isValid ) throw new Error ( 'Block mining invalid' ) ;
769796
770797 if ( this . isCurrencyMode ( ) || this . isPayloadMode ( ) ) this . updateBalance ( newBlock ) ;
771- this . chain . push ( newBlock ) ;
798+ this . #getChain ( ) . push ( newBlock ) ;
772799 this . #emit( TinyChainEvents . NewBlock , newBlock ) ;
773800 return newBlock ;
774801 } ;
@@ -798,7 +825,7 @@ class TinyChainInstance {
798825 if ( ! isValid ) throw new Error ( 'Invalid block cannot be added to the chain.' ) ;
799826
800827 if ( this . isCurrencyMode ( ) || this . isPayloadMode ( ) ) this . updateBalance ( minedBlock ) ;
801- this . chain . push ( minedBlock ) ;
828+ this . #getChain ( ) . push ( minedBlock ) ;
802829 this . #emit( TinyChainEvents . NewBlock , minedBlock ) ;
803830 return minedBlock ;
804831 } ) ;
@@ -823,7 +850,7 @@ class TinyChainInstance {
823850 * @returns {TinyChainBlock } The latest block in the blockchain.
824851 */
825852 getLatestBlock ( ) {
826- return this . getChainBlock ( this . chain . length - 1 ) ;
853+ return this . getChainBlock ( this . #getChain ( ) . length - 1 ) ;
827854 }
828855
829856 /**
@@ -841,9 +868,10 @@ class TinyChainInstance {
841868 this . balances = { } ;
842869 this . #emit( TinyChainEvents . BalancesInitialized , this . balances ) ;
843870 if ( this . isCurrencyMode ( ) ) {
871+ const balances = this . #getBalances( ) ;
844872 for ( const [ address , balance ] of Object . entries ( this . getInitialBalances ( ) ) ) {
845- this . balances [ address ] = BigInt ( balance ) ;
846- this . #emit( TinyChainEvents . BalanceStarted , address , this . balances [ address ] ) ;
873+ balances [ address ] = BigInt ( balance ) ;
874+ this . #emit( TinyChainEvents . BalanceStarted , address , balances [ address ] ) ;
847875 }
848876 }
849877 }
@@ -860,7 +888,7 @@ class TinyChainInstance {
860888 * @throws {Error } If the list is not an array, if any transfer is malformed,
861889 * or if the sender is unauthorized or lacks balance.
862890 */
863- validateTransfers ( pubKey , addressType , transfers , balances = this . balances ) {
891+ validateTransfers ( pubKey , addressType , transfers , balances = this . #getBalances ( ) ) {
864892 const isAdmin = this . getAdmins ( ) . has ( pubKey ) ;
865893 const address = this . #signer. getAddress ( Buffer . from ( pubKey , 'hex' ) , addressType ) ;
866894
@@ -911,7 +939,7 @@ class TinyChainInstance {
911939 *
912940 * @returns {void } This method does not return any value.
913941 */
914- updateBalance ( block , balances = this . balances , emitEvents = true ) {
942+ updateBalance ( block , balances = this . #getBalances ( ) , emitEvents = true ) {
915943 const reward = block . reward ;
916944 const minerAddress = block . miner ;
917945 const isMinerAddress = typeof minerAddress === 'string' && minerAddress . length > 0 ;
@@ -1039,7 +1067,7 @@ class TinyChainInstance {
10391067 if ( ! this . isCurrencyMode ( ) ) throw new Error ( 'Currency mode must be enabled.' ) ;
10401068 /** @type {Balances } */
10411069 const result = { } ;
1042- for ( const [ addr , amount ] of Object . entries ( this . balances ) ) result [ addr ] = amount ;
1070+ for ( const [ addr , amount ] of Object . entries ( this . #getBalances ( ) ) ) result [ addr ] = amount ;
10431071 return result ;
10441072 }
10451073
@@ -1059,18 +1087,19 @@ class TinyChainInstance {
10591087 * @throws {Error } Throws if `currencyMode` is disabled or if the index is invalid.
10601088 */
10611089 getBalancesAt ( startIndex = 0 , endIndex = null ) {
1090+ const chainList = this . #getChain( ) ;
10621091 if ( ! this . isCurrencyMode ( ) && ! this . isPayloadMode ( ) )
10631092 throw new Error ( 'Currency mode or payload mode must be enabled.' ) ;
1064- const end = endIndex !== null ? endIndex : this . chain . length - 1 ;
1065- if ( startIndex < 0 || end >= this . chain . length || startIndex > end )
1093+ const end = endIndex !== null ? endIndex : chainList . length - 1 ;
1094+ if ( startIndex < 0 || end >= chainList . length || startIndex > end )
10661095 throw new Error ( 'Invalid startIndex or endIndex range.' ) ;
10671096
10681097 /** @type {Balances } */
10691098 const balances = { } ;
10701099 for ( const [ address , balance ] of Object . entries ( this . getInitialBalances ( ) ) )
10711100 balances [ address ] = BigInt ( balance ) ;
10721101
1073- const chain = this . chain . slice ( startIndex , end + 1 ) ;
1102+ const chain = chainList . slice ( startIndex , end + 1 ) ;
10741103 for ( const block of chain ) this . updateBalance ( block , balances , false ) ;
10751104
10761105 return balances ;
@@ -1101,7 +1130,8 @@ class TinyChainInstance {
11011130 */
11021131 getBalance ( address ) {
11031132 if ( ! this . isCurrencyMode ( ) ) throw new Error ( 'Currency mode must be enabled.' ) ;
1104- if ( typeof this . balances [ address ] === 'bigint' ) return this . balances [ address ] ;
1133+ const balances = this . #getBalances( ) ;
1134+ if ( typeof balances [ address ] === 'bigint' ) return balances [ address ] ;
11051135 return 0n ;
11061136 }
11071137
@@ -1119,8 +1149,8 @@ class TinyChainInstance {
11191149 recalculateBalances ( ) {
11201150 this . startBalances ( ) ;
11211151 if ( this . isCurrencyMode ( ) || this . isPayloadMode ( ) )
1122- for ( const block of this . chain ) this . updateBalance ( block ) ;
1123- this . #emit( TinyChainEvents . BalanceRecalculated , this . balances ) ;
1152+ for ( const block of this . #getChain ( ) ) this . updateBalance ( block ) ;
1153+ this . #emit( TinyChainEvents . BalanceRecalculated , this . #getBalances ( ) ) ;
11241154 }
11251155
11261156 /**
@@ -1141,8 +1171,9 @@ class TinyChainInstance {
11411171 * @throws {Error } If the block at the given index does not exist.
11421172 */
11431173 getChainBlock ( index ) {
1144- if ( ! this . chain [ index ] ) throw new Error ( `The chain data ${ index } don't exist!` ) ;
1145- return this . chain [ index ] ;
1174+ const chain = this . #getChain( ) ;
1175+ if ( ! chain [ index ] ) throw new Error ( `The chain data ${ index } don't exist!` ) ;
1176+ return chain [ index ] ;
11461177 }
11471178
11481179 /**
@@ -1164,7 +1195,7 @@ class TinyChainInstance {
11641195 * @returns {GetTransactionData[] } An array containing all blocks' data.
11651196 */
11661197 getAllChainData ( ) {
1167- return this . chain . map ( ( block ) => block . get ( ) ) ;
1198+ return this . #getChain ( ) . map ( ( block ) => block . get ( ) ) ;
11681199 }
11691200
11701201 /**
@@ -1195,11 +1226,12 @@ class TinyChainInstance {
11951226 * @throws {Error } If indices are out of bounds or invalid.
11961227 */
11971228 exportChain ( startIndex = 0 , endIndex = null ) {
1198- const end = endIndex !== null ? endIndex : this . chain . length - 1 ;
1199- if ( startIndex < 0 || end >= this . chain . length || startIndex > end )
1229+ const chain = this . #getChain( ) ;
1230+ const end = endIndex !== null ? endIndex : chain . length - 1 ;
1231+ if ( startIndex < 0 || end >= chain . length || startIndex > end )
12001232 throw new Error ( 'Invalid startIndex or endIndex range.' ) ;
12011233
1202- return this . chain . slice ( startIndex , end + 1 ) . map ( ( b ) => b . export ( ) ) ;
1234+ return chain . slice ( startIndex , end + 1 ) . map ( ( b ) => b . export ( ) ) ;
12031235 }
12041236
12051237 /**
@@ -1223,7 +1255,7 @@ class TinyChainInstance {
12231255 const isValid = this . isValid ( ) ;
12241256 if ( isValid === null ) throw new Error ( 'The data chain is null or corrupted.' ) ;
12251257 if ( ! isValid ) throw new Error ( 'The data chain is invalid or corrupted.' ) ;
1226- this . #emit( TinyChainEvents . ImportChain , this . chain ) ;
1258+ this . #emit( TinyChainEvents . ImportChain , this . #getChain ( ) ) ;
12271259 }
12281260
12291261 /**
0 commit comments