import BigNumber from 'bignumber.js' ; import { toChecksumAddress } from 'ethereumjs-util' ; import * as rlp from 'rlp' ; import { Address } from './address' ; const ISTANBUL_EXTRA_VANITY_BYTES = 32 ; export type Bitmap = BigNumber ; export interface Seal { bitmap : Bitmap ; signature : string ; round : BigNumber ; } export interface IstanbulExtra { addedValidators : Address [ ] ; addedValidatorsPublicKeys : string [ ] ; removedValidators : Bitmap ; seal : string ; aggregatedSeal : Seal ; parentAggregatedSeal : Seal ; } function bigNumberFromBuffer ( data ) { return new BigNumber ( '0x' + ( data . toString ( 'hex' ) || '0' ) , 16 ) ; } function sealFromBuffers ( data ) { return { bitmap : bigNumberFromBuffer ( data [ 0 ] ) , signature : '0x' + data [ 1 ] . toString ( 'hex' ) , round : bigNumberFromBuffer ( data [ 2 ] ) } ; } export function parseBlockExtraData ( data ) { const buffer = Buffer . from ( data . replace ( /^0x/ , '' ) , 'hex' ) ; const decode = rlp . decode ( '0x' + buffer . slice ( ISTANBUL_EXTRA_VANITY_BYTES ) . toString ( 'hex' ) ) ; return { addedValidators : decode [ 0 ] . map ( ( addr ) => toChecksumAddress ( addr . toString ( 'hex' ) ) ) , addedValidatorsPublicKeys : decode [ 1 ] . map ( ( key ) => '0x' + key . toString ( 'hex' ) ) , removedValidators : bigNumberFromBuffer ( decode [ 2 ] ) , seal : '0x' + decode [ 3 ] . toString ( 'hex' ) , aggregatedSeal : sealFromBuffers ( decode [ 4 ] ) , parentAggregatedSeal : sealFromBuffers ( decode [ 5 ] ) } ; } export function bitIsSet ( bitmap , index ) { if ( index < 0 ) { throw new Error ( `bit index must be greater than zero: got ${ index }` ) ; } return bitmap . idiv ( '1' + '0' . repeat ( index ) , 2 ) . mod ( 2 ) . gt ( 0 ) ; } export const IstanbulUtils = { parseBlockExtraData , bitIsSet } ;