1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
crate::ix!();

pub trait MaybePunishNodeForBlock {

    fn maybe_punish_node_for_block(&self, 
        nodeid:            NodeId,
        state:             &BlockValidationState,
        via_compact_block: bool,
        message:           Option<&str>) -> bool;
}
    
impl MaybePunishNodeForBlock for PeerManager {

    /**
      | Potentially mark a node discouraged
      | based on the contents of a BlockValidationState
      | object
      | 
      | -----------
      | @param[in] via_compact_block
      | 
      | this bool is passed in because net_processing
      | should punish peers differently depending
      | on whether the data was provided in a
      | compact block message or not. If the
      | compact block had a valid header, but
      | contained invalid txs, the peer should
      | not be punished. See BIP 152.
      | 
      | -----------
      | @return
      | 
      | Returns true if the peer was punished
      | (probably disconnected)
      |
      */
    fn maybe_punish_node_for_block(&self, 
        nodeid:            NodeId,
        state:             &BlockValidationState,
        via_compact_block: bool,
        message:           Option<&str>) -> bool {

        let message: &str = message.unwrap_or("");
        
        match state.get_result() {

            BlockValidationResult::BLOCK_RESULT_UNSET  => { },

            BlockValidationResult::BLOCK_CONSENSUS 
                | BlockValidationResult::BLOCK_MUTATED => {

                //  The node is providing invalid data:
                if !via_compact_block {
                    self.misbehaving(nodeid, 100, message);
                    return true;
                }
            },

            BlockValidationResult::BLOCK_CACHED_INVALID  => {

                let mut guard = CS_MAIN.lock();

                let node_state: Amo<NodeState> = create_state(nodeid);

                if node_state.is_some() {

                    // Discourage outbound (but not
                    // inbound) peers if on an invalid
                    // chain.
                    //
                    // Exempt HB compact block
                    // peers. Manual connections are
                    // always protected from
                    // discouragement.
                    if !via_compact_block && !node_state.get().is_inbound.load(atomic::Ordering::Relaxed) {
                        self.misbehaving(nodeid, 100, message);
                        return true;
                    }
                }
            },

            BlockValidationResult::BLOCK_INVALID_HEADER  
                | BlockValidationResult::BLOCK_CHECKPOINT 
                | BlockValidationResult::BLOCK_INVALID_PREV => {

                self.misbehaving(nodeid, 100, message);
                return true;
            },

            // Conflicting (but not necessarily
            // invalid) data or different policy:
            BlockValidationResult::BLOCK_MISSING_PREV  => {

                // TODO: Handle this much more
                // gracefully (10 DoS points is
                // super arbitrary)
                self.misbehaving(nodeid,10,message);
                return true;
            },

            BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE  
                | BlockValidationResult::BLOCK_TIME_FUTURE => { },
        }

        if message != "" {
            log_print!(LogFlags::NET, "peer=%d: %s\n", nodeid, message);
        }

        false
    }
}