import BigInt from '../../common/bigInt' ; import { GENESIS_BLOCK_TIMESTAMP } from '../../consts' ; import { Address } from '../../crypto' ; import { ERROR_CODE } from '../../error' ; import RestClient from '../../network/rest/restClient' ; import { Transaction } from '../../transaction/transaction' ; import { makeNativeContractTx } from '../../transaction/transactionUtils' ; import { bigIntFromBytes , calcUnboundOng , hex2VarBytes , hexstr2str , num2hexstring , str2hexstr , str2VarBytes , StringReader , varifyPositiveInt } from '../../utils' ; import { buildNativeCodeScript } from '../abi/nativeVmParamsBuilder' ; import Struct from '../abi/struct' ; const GOVERNANCE_CONTRACT = '0000000000000000000000000000000000000007' ; const PEER_ATTRIBUTES = 'peerAttributes' ; const SPLIT_FEE_ADDRESS = 'splitFeeAddress' ; const AUTHORIZE_INFO_POOL = 'voteInfoPool' ; const GLOBAL_PARAM = 'globalParam' ; const TOTAL_STAKE = 'totalStake' ; const VBFT_CONFIG = 'vbftConfig' ; const contractAddress = new Address ( GOVERNANCE_CONTRACT ) ; param ontid param peerPubKey param userAddr param keyNo param initPos param payer param gasPrice param gasLimit export function makeRegisterCandidateTx ( ontid , peerPubKey , keyNo , userAddr , initPos , payer , gasPrice , gasLimit ) { if ( typeof initPos !== 'number' ) { throw new Error ( 'Parameter initPos must be number!' ) ; } varifyPositiveInt ( initPos ) ; if ( ontid . substr ( 0 , 3 ) === 'did' ) { ontid = str2hexstr ( ontid ) ; } const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubKey ) , userAddr . serialize ( ) , initPos , ontid , keyNo ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'registerCandidate' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param userAddr param peerPubKey param payer param gasPrice param gasLimit export function makeUnregisterCandidateTx ( userAddr , peerPubKey , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubKey ) , userAddr . serialize ( ) ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'unRegisterCandidate' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param peerPubKey param payer param gasPrice param gasLimit export function makeApproveCandidateTx ( peerPubKey , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubKey ) ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'approveCandidate' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param peerPubKey param payer param gasPrice param gasLimit export function makeRejectCandidateTx ( peerPubKey , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubKey ) ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'rejectCandidate' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param userAddr param peerPubKeys param posList param payer param gasPrice param gasLimit export function makeVoteForPeerTx ( userAddr , peerPubKeys , posList , payer , gasPrice , gasLimit ) { if ( peerPubKeys . length !== posList . length ) { throw ERROR_CODE . INVALID_PARAMS ; } const struct = new Struct ( ) ; struct . add ( userAddr . serialize ( ) ) ; struct . add ( peerPubKeys . length ) ; for ( const p of peerPubKeys ) { struct . add ( str2hexstr ( p ) ) ; } struct . add ( posList . length ) ; for ( const n of posList ) { struct . add ( n ) ; } const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'voteForPeer' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param userAddr param peerPubKeys param posList param payer param gasPrice param gasLimit export function makeUnvoteForPeerTx ( userAddr , peerPubKeys , posList , payer , gasPrice , gasLimit ) { if ( peerPubKeys . length !== posList . length ) { throw ERROR_CODE . INVALID_PARAMS ; } const struct = new Struct ( ) ; struct . add ( userAddr . serialize ( ) ) ; struct . add ( peerPubKeys . length ) ; for ( const p of peerPubKeys ) { struct . add ( str2hexstr ( p ) ) ; } struct . add ( posList . length ) ; for ( const n of posList ) { struct . add ( n ) ; } const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'unVoteForPeer' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param userAddr param peerPubKeys param withdrawList export function makeWithdrawTx ( userAddr , peerPubKeys , withdrawList , payer , gasPrice , gasLimit ) { if ( peerPubKeys . length !== withdrawList . length ) { throw ERROR_CODE . INVALID_PARAMS ; } const struct = new Struct ( ) ; struct . add ( userAddr . serialize ( ) ) ; struct . add ( peerPubKeys . length ) ; for ( const p of peerPubKeys ) { struct . add ( str2hexstr ( p ) ) ; } struct . add ( withdrawList . length ) ; for ( const w of withdrawList ) { struct . add ( w ) ; } const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'withdraw' , params , contractAddress , gasPrice , gasLimit , payer ) ; } /** Quit node register
 * Need two signatures if userAddr and payer are not the same
 */ export function makeQuitNodeTx ( userAddr , peerPubKey , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubKey ) , userAddr . serialize ( ) ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'quitNode' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param peerPubKey param userAddr param maxAuthorize param payer param gasPrice param gasLimit export function makeChangeAuthorizationTx ( peerPubKey , userAddr , maxAuthorize , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubKey ) , userAddr . serialize ( ) , maxAuthorize ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'changeMaxAuthorization' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param peerPubKey param userAddr param peerCost param payer param gasPrice param gasLimit export function makeSetPeerCostTx ( peerPubKey , userAddr , peerCost , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubKey ) , userAddr . serialize ( ) , peerCost ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'setPeerCost' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param peerPubKey param userAddr param peerCost param stakeCost param payer param gasPrice param gasLimit export function makeSetFeePercentageTx ( peerPubKey , userAddr , peerCost , stakeCost , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubKey ) , userAddr . serialize ( ) , peerCost , stakeCost ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'setFeePercentage' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param userAddr param payer param gasPrice param gasLimit export function makeWithdrawFeeTx ( userAddr , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( userAddr . serialize ( ) ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'withdrawFee' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param userAddr param peerPubKeyList param posList param payer param gasPrice param gasLimit export function makeAuthorizeForPeerTx ( userAddr , peerPubKeyList , posList , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( userAddr . serialize ( ) ) ; struct . add ( peerPubKeyList . length ) ; for ( const p of peerPubKeyList ) { struct . add ( str2hexstr ( p ) ) ; } struct . add ( posList . length ) ; for ( const w of posList ) { struct . add ( w ) ; } const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'authorizeForPeer' , params , contractAddress , gasPrice , gasLimit , payer ) ; } /**
 * User cancels the authorization of peer
 */ export function makeUnauthorizeForPeerTx ( userAddr , peerPubKeyList , posList , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( userAddr . serialize ( ) ) ; struct . add ( peerPubKeyList . length ) ; for ( const p of peerPubKeyList ) { struct . add ( str2hexstr ( p ) ) ; } struct . add ( posList . length ) ; for ( const w of posList ) { struct . add ( w ) ; } const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'unAuthorizeForPeer' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param peerPubkey param userAddr param pos param payer param gasPrice param gasLimit export function makeAddInitPosTx ( peerPubkey , userAddr , pos , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubkey ) , userAddr . serialize ( ) , pos ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'addInitPos' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param peerPubkey param userAddr param pos param payer param gasPrice param gasLimit export function makeReduceInitPosTx ( peerPubkey , userAddr , pos , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( str2hexstr ( peerPubkey ) , userAddr . serialize ( ) , pos ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'reduceInitPos' , params , contractAddress , gasPrice , gasLimit , payer ) ; } export function makeWithdrawPeerUnboundOngTx ( userAddr , payer , gasPrice , gasLimit ) { const struct = new Struct ( ) ; struct . add ( userAddr . serialize ( ) ) ; const params = buildNativeCodeScript ( [ struct ] ) ; return makeNativeContractTx ( 'withdrawOng' , params , contractAddress , gasPrice , gasLimit , payer ) ; } param peerPubKey param url export async function getAttributes ( peerPubKey , url ? ) { const restClient = new RestClient ( url ) ; const codeHash = contractAddress . toHexString ( ) ; const key = str2hexstr ( PEER_ATTRIBUTES ) + peerPubKey ; const res = await restClient . getStorage ( codeHash , key ) ; const result = res . Result ; if ( result ) { const peerAttributes = PeerAttributes . deserialize ( new StringReader ( result ) ) ; if ( peerAttributes . t2StakeCost === 0 ) { peerAttributes . t2StakeCost = peerAttributes . t2PeerCost ; } if ( peerAttributes . t1StakeCost === 0 ) { peerAttributes . t1StakeCost = peerAttributes . t1PeerCost ; } if ( peerAttributes . tStakeCost === 0 ) { peerAttributes . tStakeCost = peerAttributes . tPeerCost ; } if ( peerAttributes . t2StakeCost === 101 ) { peerAttributes . t2StakeCost = 0 ; } if ( peerAttributes . t1StakeCost === 101 ) { peerAttributes . t1StakeCost = 0 ; } if ( peerAttributes . tStakeCost === 101 ) { peerAttributes . tStakeCost = 0 ; } return peerAttributes ; } else { return new PeerAttributes ( ) ; } } param address param url export async function getSplitFeeAddress ( address , url ? ) { const restClient = new RestClient ( url ) ; const codeHash = contractAddress . toHexString ( ) ; const key = str2hexstr ( SPLIT_FEE_ADDRESS ) + address . serialize ( ) ; const res = await restClient . getStorage ( codeHash , key ) ; const result = res . Result ; if ( result ) { return SplitFeeAddress . deserialize ( new StringReader ( result ) ) ; } else { return new SplitFeeAddress ( ) ; } } param peerPubKey param address param url export async function getAuthorizeInfo ( peerPubKey , address , url ? ) { const restClient = new RestClient ( url ) ; const codeHash = contractAddress . toHexString ( ) ; const key = str2hexstr ( AUTHORIZE_INFO_POOL ) + peerPubKey + address . serialize ( ) ; const res = await restClient . getStorage ( codeHash , key ) ; const result = res . Result ; if ( result ) { return AuthorizeInfo . deserialize ( new StringReader ( result ) ) ; } else { return new AuthorizeInfo ( ) ; } } param url export async function getGovernanceView ( url ? ) { const restClient = new RestClient ( url ) ; const codeHash = contractAddress . toHexString ( ) ; const key = str2hexstr ( 'governanceView' ) ; const viewRes = await restClient . getStorage ( codeHash , key ) ; const view = viewRes . Result ; const governanceView = GovernanceView . deserialize ( new StringReader ( view ) ) ; return governanceView ; } param url export async function getPeerPoolMap ( url ? ) { const restClient = new RestClient ( url ) ; const codeHash = contractAddress . toHexString ( ) ; const governanceView = await getGovernanceView ( url ) ; const key1 = str2hexstr ( 'peerPool' ) ; const key2 = num2hexstring ( governanceView . view , 4 , true ) ; const keyP = key1 + key2 ; const res = await restClient . getStorage ( codeHash , keyP ) ; const sr = new StringReader ( res . Result ) ; const length = sr . readInt ( ) ; const result = { } ; for ( let i = 0 ; i < length ; i ++ ) { const p = PeerPoolItem . deserialize ( sr ) ; result [ p . peerPubkey ] = p ; } return result ; } export async function getGlobalParam ( url ? ) { const restClient = new RestClient ( url ) ; const codeHash = contractAddress . toHexString ( ) ; const key = str2hexstr ( GLOBAL_PARAM ) ; const res = await restClient . getStorage ( codeHash , key ) ; if ( res . Result ) { return GlobalParam . deserialize ( new StringReader ( res . Result ) ) ; } else { return new GlobalParam ( ) ; } } export async function getTotalStake ( userAddr , url ? ) { const restClient = new RestClient ( url ) ; const codeHash = contractAddress . toHexString ( ) ; const key = str2hexstr ( TOTAL_STAKE ) + userAddr . serialize ( ) ; const res = await restClient . getStorage ( codeHash , key ) ; if ( res . Result ) { return TotalStake . deserialize ( new StringReader ( res . Result ) ) ; } else { return new TotalStake ( ) ; } } export async function getPeerUnboundOng ( userAddr , url ? ) { const totalStake = await getTotalStake ( userAddr , url ) ; if ( ! totalStake . address ) { return 0 ; } const restClient = new RestClient ( url ) ; const blockHeight = ( await restClient . getBlockHeight ( ) ) . Result ; const block = ( await restClient . getBlockJson ( blockHeight ) ) . Result ; const timeStamp = block . Header . Timestamp - GENESIS_BLOCK_TIMESTAMP ; return calcUnboundOng ( totalStake . stake , totalStake . timeOffset , timeStamp ) ; } export async function getConfiguration ( url ? ) { const restClient = new RestClient ( url ) ; const codeHash = contractAddress . toHexString ( ) ; const key = str2hexstr ( VBFT_CONFIG ) ; const res = await restClient . getStorage ( codeHash , key ) ; if ( res . Result ) { return Configuration . deserialize ( new StringReader ( res . Result ) ) ; } else { return new Configuration ( ) ; } } /**
 * Use to store governance state.
 */ export class GovernanceView { static deserialize ( sr ) { const g = new GovernanceView ( ) ; g . view = sr . readUint32 ( ) ; g . height = sr . readUint32 ( ) ; g . txhash = sr . read ( 64 ) ; return g ; } view : number = 0 ; height : number = 0 ; txhash : string = '' ; serialize ( ) { let result = '' ; result += num2hexstring ( this . view , 4 , true ) ; result += num2hexstring ( this . height , 4 , true ) ; result += hex2VarBytes ( this . txhash ) ; return result ; } } /**
 * Describs the peer's state in the pool.
 */ export class PeerPoolItem { static deserialize ( sr ) { const p = new PeerPoolItem ( ) ; p . index = sr . readInt ( ) ; p . peerPubkey = hexstr2str ( sr . readNextBytes ( ) ) ; p . address = Address . deserialize ( sr ) ; p . status = parseInt ( sr . read ( 1 ) , 16 ) ; p . initPos = sr . readLong ( ) ; p . totalPos = sr . readLong ( ) ; return p ; } index : number = 0 ; peerPubkey : string = '' ; address : Address ; status : number = 0 ; initPos : number = 0 ; totalPos : number = 0 ; serialize ( ) { let result = '' ; result += num2hexstring ( this . index , 4 , true ) ; result += str2VarBytes ( this . peerPubkey ) ; result += this . address . serialize ( ) ; result += num2hexstring ( this . status ) ; result += num2hexstring ( this . initPos , 8 , true ) ; result += num2hexstring ( this . totalPos , 8 , true ) ; return result ; } } export class PeerAttributes { static deserialize ( sr ) { const pr = new PeerAttributes ( ) ; pr . peerPubkey = hexstr2str ( sr . readNextBytes ( ) ) ; pr . maxAuthorize = sr . readLong ( ) ; pr . t2PeerCost = sr . readLong ( ) ; pr . t1PeerCost = sr . readLong ( ) ; pr . tPeerCost = sr . readLong ( ) ; pr . t2StakeCost = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; pr . t1StakeCost = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; pr . tStakeCost = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; pr . field4 = sr . readNextBytes ( ) ; return pr ; } peerPubkey : string = '' ; maxAuthorize : number = 0 ; t2PeerCost : number = 100 ; t1PeerCost : number = 100 ; tPeerCost : number = 100 ; t2StakeCost : number = 100 ; t1StakeCost : number = 100 ; tStakeCost : number = 100 ; field4 : string = '' ; serialize ( ) { return '' ; } } export class SplitFeeAddress { static deserialize ( sr ) { const sfa = new SplitFeeAddress ( ) ; sfa . address = Address . deserialize ( sr ) ; sfa . amount = sr . readLong ( ) ; return sfa ; } address : Address ; amount : number = 0 ; } export class AuthorizeInfo { static deserialize ( sr ) { const ai = new AuthorizeInfo ( ) ; ai . peerPubkey = hexstr2str ( sr . readNextBytes ( ) ) ; ai . address = Address . deserialize ( sr ) ; ai . consensusPos = sr . readLong ( ) ; ai . freezePos = sr . readLong ( ) ; ai . newPos = sr . readLong ( ) ; ai . withdrawPos = sr . readLong ( ) ; ai . withdrawFreezePos = sr . readLong ( ) ; ai . withdrawUnfreezePos = sr . readLong ( ) ; return ai ; } peerPubkey : string = '' ; address : Address ; consensusPos : number = 0 ; freezePos : number = 0 ; newPos : number = 0 ; withdrawPos : number = 0 ; withdrawFreezePos : number = 0 ; withdrawUnfreezePos : number = 0 ; } export class GlobalParam { static deserialize ( sr ) { const gp = new GlobalParam ( ) ; const feeHexStr = sr . readNextBytes ( ) ; const candidateFeeStr = BigInt . fromHexstr ( feeHexStr ) . value ; gp . candidateFee = Number ( candidateFeeStr ) ; const minStr = BigInt . fromHexstr ( sr . readNextBytes ( ) ) . value ; gp . minInitState = Number ( minStr ) ; const candidateNumStr = BigInt . fromHexstr ( sr . readNextBytes ( ) ) . value ; const candidateNum = Number ( candidateNumStr ) ; gp . candidateNum = candidateNum ; const posLimitStr = BigInt . fromHexstr ( sr . readNextBytes ( ) ) . value ; gp . posLimit = Number ( posLimitStr ) ; const aStr = BigInt . fromHexstr ( sr . readNextBytes ( ) ) . value ; const a = Number ( aStr ) ; const bStr = BigInt . fromHexstr ( sr . readNextBytes ( ) ) . value ; const b = Number ( bStr ) ; const yStr = BigInt . fromHexstr ( sr . readNextBytes ( ) ) . value ; const yita = Number ( yStr ) ; const pStr = BigInt . fromHexstr ( sr . readNextBytes ( ) ) . value ; const penalty = Number ( pStr ) ; gp . A = a ; gp . B = b ; gp . yita = yita ; gp . penalty = penalty ; return gp ; } candidateFee : number ; candidateNum : number ; minInitState : number ; posLimit : number ; A : number ; B : number ; yita : number ; penalty : number ; } export class TotalStake { static deserialize ( sr ) { const ts = new TotalStake ( ) ; ts . address = Address . deserialize ( sr ) ; ts . stake = sr . readLong ( ) ; ts . timeOffset = sr . readUint32 ( ) ; return ts ; } address : Address ; stake : number ; timeOffset : number ; } export class Configuration { static deserialize ( sr ) { const config = new Configuration ( ) ; config . N = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; config . C = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; config . K = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; config . L = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; config . BlockMsgDelay = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; config . HashMsgDelay = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; config . PeerHandShakeTimeout = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; config . MaxBlockChangeView = Number ( bigIntFromBytes ( sr . readNextBytes ( ) ) ) ; return config ; } N : number ; C : number ; K : number ; L : number ; BlockMsgDelay : number ; HashMsgDelay : number ; PeerHandShakeTimeout : number ; MaxBlockChangeView : number ; }