@@ -2948,12 +2948,20 @@ pub fn run_dr_locally(dr: &DataRequestOutput) -> Result<RadonTypes, failure::Err
29482948mod tests {
29492949 use crate :: utils:: test_actix_system;
29502950 use witnet_config:: { config:: consensus_constants_from_partial, defaults:: Testnet } ;
2951+ use witnet_crypto:: signature:: sign;
29512952 use witnet_data_structures:: {
29522953 chain:: {
2953- ChainInfo , Environment , KeyedSignature , PartialConsensusConstants , PublicKey ,
2954- ValueTransferOutput ,
2954+ BlockMerkleRoots , BlockTransactions , ChainInfo , Environment , KeyedSignature ,
2955+ PartialConsensusConstants , PublicKey , SecretKey , Signature , ValueTransferOutput ,
29552956 } ,
2956- transaction:: { CommitTransaction , DRTransaction , RevealTransaction } ,
2957+ transaction:: { CommitTransaction , DRTransaction , MintTransaction , RevealTransaction } ,
2958+ vrf:: BlockEligibilityClaim ,
2959+ } ;
2960+ use witnet_protected:: Protected ;
2961+ use witnet_validations:: validations:: { block_reward, merkle_tree_root} ;
2962+
2963+ use secp256k1:: {
2964+ PublicKey as Secp256k1_PublicKey , Secp256k1 , SecretKey as Secp256k1_SecretKey ,
29572965 } ;
29582966
29592967 use super :: * ;
@@ -3368,4 +3376,186 @@ mod tests {
33683376 ]
33693377 ) ;
33703378 }
3379+
3380+ static PRIV_KEY_1 : [ u8 ; 32 ] = [ 0xcd ; 32 ] ;
3381+ static PRIV_KEY_2 : [ u8 ; 32 ] = [ 0x43 ; 32 ] ;
3382+
3383+ fn build_merkle_tree ( block_header : & mut BlockHeader , txns : & BlockTransactions ) {
3384+ let merkle_roots = BlockMerkleRoots {
3385+ mint_hash : txns. mint . hash ( ) ,
3386+ vt_hash_merkle_root : merkle_tree_root ( & txns. value_transfer_txns ) ,
3387+ dr_hash_merkle_root : merkle_tree_root ( & txns. data_request_txns ) ,
3388+ commit_hash_merkle_root : merkle_tree_root ( & txns. commit_txns ) ,
3389+ reveal_hash_merkle_root : merkle_tree_root ( & txns. reveal_txns ) ,
3390+ tally_hash_merkle_root : merkle_tree_root ( & txns. tally_txns ) ,
3391+ } ;
3392+ block_header. merkle_roots = merkle_roots;
3393+ }
3394+
3395+ fn sign_tx < H : Hashable > ( mk : [ u8 ; 32 ] , tx : & H ) -> KeyedSignature {
3396+ let Hash :: SHA256 ( data) = tx. hash ( ) ;
3397+
3398+ let secp = & Secp256k1 :: new ( ) ;
3399+ let secret_key =
3400+ Secp256k1_SecretKey :: from_slice ( & mk) . expect ( "32 bytes, within curve order" ) ;
3401+ let public_key = Secp256k1_PublicKey :: from_secret_key ( secp, & secret_key) ;
3402+ let public_key = PublicKey :: from ( public_key) ;
3403+
3404+ let signature = sign ( secp, secret_key, & data) . unwrap ( ) ;
3405+
3406+ KeyedSignature {
3407+ signature : Signature :: from ( signature) ,
3408+ public_key,
3409+ }
3410+ }
3411+
3412+ fn create_valid_block ( chain_manager : & mut ChainManager , priv_key : & [ u8 ; 32 ] ) -> Block {
3413+ let vrf = & mut VrfCtx :: secp256k1 ( ) . unwrap ( ) ;
3414+ let current_epoch = chain_manager. current_epoch . unwrap ( ) ;
3415+
3416+ let consensus_constants = chain_manager. consensus_constants ( ) ;
3417+ let secret_key = SecretKey {
3418+ bytes : Protected :: from ( priv_key. to_vec ( ) ) ,
3419+ } ;
3420+ let last_block_hash = chain_manager
3421+ . chain_state
3422+ . chain_info
3423+ . as_ref ( )
3424+ . unwrap ( )
3425+ . highest_block_checkpoint
3426+ . hash_prev_block ;
3427+ let last_vrf_input = chain_manager
3428+ . chain_state
3429+ . chain_info
3430+ . as_ref ( )
3431+ . unwrap ( )
3432+ . highest_vrf_output
3433+ . hash_prev_vrf ;
3434+ let block_beacon = CheckpointBeacon {
3435+ checkpoint : current_epoch,
3436+ hash_prev_block : last_block_hash,
3437+ } ;
3438+
3439+ let vrf_input = CheckpointVRF {
3440+ checkpoint : current_epoch,
3441+ hash_prev_vrf : last_vrf_input,
3442+ } ;
3443+
3444+ let my_pkh = PublicKeyHash :: default ( ) ;
3445+
3446+ let txns = BlockTransactions {
3447+ mint : MintTransaction :: new (
3448+ current_epoch,
3449+ vec ! [ ValueTransferOutput {
3450+ time_lock: 0 ,
3451+ pkh: my_pkh,
3452+ value: block_reward(
3453+ current_epoch,
3454+ consensus_constants. initial_block_reward,
3455+ consensus_constants. halving_period,
3456+ ) ,
3457+ } ] ,
3458+ ) ,
3459+ ..BlockTransactions :: default ( )
3460+ } ;
3461+
3462+ let mut block_header = BlockHeader :: default ( ) ;
3463+ build_merkle_tree ( & mut block_header, & txns) ;
3464+ block_header. beacon = block_beacon;
3465+ block_header. proof = BlockEligibilityClaim :: create ( vrf, & secret_key, vrf_input) . unwrap ( ) ;
3466+
3467+ let block_sig = sign_tx ( * priv_key, & block_header) ;
3468+
3469+ Block :: new ( block_header, block_sig, txns)
3470+ }
3471+
3472+ #[ test]
3473+ fn test_process_candidate_malleability ( ) {
3474+ let _ = env_logger:: builder ( ) . is_test ( true ) . try_init ( ) ;
3475+ test_actix_system ( || async {
3476+ let mut chain_manager = ChainManager :: default ( ) ;
3477+
3478+ chain_manager. current_epoch = Some ( 2000000 ) ;
3479+ // 1 epoch = 1000 seconds, for easy testing
3480+ chain_manager. epoch_constants = Some ( EpochConstants {
3481+ checkpoint_zero_timestamp : 0 ,
3482+ checkpoints_period : 1_000 ,
3483+ } ) ;
3484+ chain_manager. chain_state . chain_info = Some ( ChainInfo {
3485+ environment : Environment :: default ( ) ,
3486+ consensus_constants : consensus_constants_from_partial (
3487+ & PartialConsensusConstants :: default ( ) ,
3488+ & Testnet ,
3489+ ) ,
3490+ highest_block_checkpoint : CheckpointBeacon :: default ( ) ,
3491+ highest_superblock_checkpoint : CheckpointBeacon {
3492+ checkpoint : 0 ,
3493+ hash_prev_block : Hash :: SHA256 ( [ 1 ; 32 ] ) ,
3494+ } ,
3495+ highest_vrf_output : CheckpointVRF :: default ( ) ,
3496+ } ) ;
3497+ chain_manager. chain_state . reputation_engine = Some ( ReputationEngine :: new ( 1000 ) ) ;
3498+ chain_manager. vrf_ctx = Some ( VrfCtx :: secp256k1 ( ) . unwrap ( ) ) ;
3499+ chain_manager. secp = Some ( Secp256k1 :: new ( ) ) ;
3500+ chain_manager. sm_state = StateMachine :: Synced ;
3501+
3502+ let block_1 = create_valid_block ( & mut chain_manager, & PRIV_KEY_2 ) ;
3503+ let block_2 = create_valid_block ( & mut chain_manager, & PRIV_KEY_1 ) ;
3504+
3505+ // block_1 should be better candidate than block_2
3506+ let vrf_ctx = & mut VrfCtx :: secp256k1 ( ) . unwrap ( ) ;
3507+ let vrf_hash_1 = block_1
3508+ . block_header
3509+ . proof
3510+ . proof
3511+ . proof_to_hash ( vrf_ctx)
3512+ . unwrap ( ) ;
3513+ let vrf_hash_2 = block_2
3514+ . block_header
3515+ . proof
3516+ . proof
3517+ . proof_to_hash ( vrf_ctx)
3518+ . unwrap ( ) ;
3519+ assert_eq ! (
3520+ compare_block_candidates(
3521+ block_1. hash( ) ,
3522+ Reputation ( 0 ) ,
3523+ vrf_hash_1,
3524+ false ,
3525+ block_2. hash( ) ,
3526+ Reputation ( 0 ) ,
3527+ vrf_hash_2,
3528+ false ,
3529+ & VrfSlots :: new( vec![ Hash :: default ( ) ] ) ,
3530+ ) ,
3531+ Ordering :: Greater
3532+ ) ;
3533+
3534+ let mut block_mal_1 = block_1. clone ( ) ;
3535+ // Malleability!
3536+ block_mal_1. txns . mint . outputs . clear ( ) ;
3537+ // Changing block txns field does not change block hash
3538+ assert_eq ! ( block_1. hash( ) , block_mal_1. hash( ) ) ;
3539+ // But the blocks are different
3540+ assert_ne ! ( block_1, block_mal_1) ;
3541+
3542+ // Process the modified candidate first
3543+ chain_manager. process_candidate ( block_mal_1) ;
3544+ // The best candidate should be None because this block is invalid
3545+ let best_cand = chain_manager. best_candidate . as_ref ( ) . map ( |bc| & bc. block ) ;
3546+ assert_eq ! ( best_cand, None ) ;
3547+
3548+ // Process candidate with the same hash, but this one is valid
3549+ chain_manager. process_candidate ( block_1. clone ( ) ) ;
3550+ // The best candidate should be block_1
3551+ let best_cand = chain_manager. best_candidate . as_ref ( ) . map ( |bc| & bc. block ) ;
3552+ assert_eq ! ( best_cand, Some ( & block_1) ) ;
3553+
3554+ // Process another valid candidate, but worse than the other one
3555+ chain_manager. process_candidate ( block_2) ;
3556+ // The best candidate should still be block_1
3557+ let best_cand = chain_manager. best_candidate . as_ref ( ) . map ( |bc| & bc. block ) ;
3558+ assert_eq ! ( best_cand, Some ( & block_1) ) ;
3559+ } ) ;
3560+ }
33713561}
0 commit comments