@@ -79,29 +79,23 @@ def receive_peer_block():
7979 if not block_data :
8080 return jsonify ({"success" : False , "message" : "No block data provided" }), 400
8181
82- # 1. Reconstruct block object
83- new_block = blockchain .block_model (
84- index = block_data ["index" ],
85- timestamp = block_data ["timestamp" ],
86- data = json .dumps (block_data ["data" ]),
87- merkle_root = block_data .get ("merkle_root" ),
88- previous_hash = block_data ["previous_hash" ],
89- nonce = block_data ["nonce" ],
90- hash = block_data ["hash" ],
91- signed_by = block_data .get ("signed_by" ),
92- signature = block_data .get ("signature" ),
93- )
82+ required_fields = {"index" , "timestamp" , "data" , "previous_hash" , "nonce" , "hash" }
83+ missing = [field for field in required_fields if field not in block_data ]
84+ if missing :
85+ return jsonify ({"success" : False , "message" : f"Missing required fields: { ', ' .join (missing )} " }), 400
9486
95- # 2. Simple validation against local chain
96- last_block = blockchain .get_latest_block ()
97- if last_block and block_data ["index" ] <= last_block .index :
98- return jsonify ({"success" : False , "message" : "Block already exists or is outdated" }), 409
87+ source_node = blockchain .normalize_node_ref (request .headers .get ("X-Node-Address" ) or request .headers .get ("X-Source-Node" ))
88+ origin_node = (request .headers .get ("X-Origin-Node" ) or request .headers .get ("X-Source-Node" ) or "unknown" ).strip ()
89+ sender_node = source_node or blockchain .normalize_node_ref (block_data .get ("proposed_by" ))
9990
100- if last_block and block_data [ "previous_hash" ] != last_block . hash :
101- return jsonify ({"success" : False , "message" : "Previous hash mismatch. Sync required. " }), 400
91+ if not blockchain . is_validator_node ( sender_node ) :
92+ return jsonify ({"success" : False , "message" : f"Unauthorized validator node: { sender_node or 'unknown' } " }), 403
10293
103- # 3. Cryptographic validation (simplified for the model bridge)
104- # Create a Block object for validation methods
94+ # Idempotency gate: if already present, ignore safely.
95+ if blockchain .has_block (block_data ["index" ], block_data ["hash" ]):
96+ return jsonify ({"success" : True , "message" : "Duplicate block ignored" }), 200
97+
98+ # 1. Validate block object before any persistence
10599 from core .blockchain import Block
106100
107101 v_block = Block (
@@ -110,6 +104,8 @@ def receive_peer_block():
110104 block_data ["previous_hash" ],
111105 signed_by = block_data .get ("signed_by" ),
112106 signature = block_data .get ("signature" ),
107+ proposed_by = block_data .get ("proposed_by" ),
108+ status = block_data .get ("status" ),
113109 )
114110 v_block .timestamp = block_data ["timestamp" ]
115111 v_block .nonce = block_data ["nonce" ]
@@ -119,16 +115,55 @@ def receive_peer_block():
119115 if v_block .hash != v_block .calculate_hash ():
120116 return jsonify ({"success" : False , "message" : "Invalid block hash" }), 400
121117
122- if blockchain .crypto_manager and v_block .signature :
118+ if v_block .merkle_root and v_block .merkle_root != v_block .calculate_merkle_root ():
119+ return jsonify ({"success" : False , "message" : "Invalid Merkle root" }), 400
120+
121+ if v_block .index > 0 and v_block .signed_by not in blockchain .VALIDATORS :
122+ return jsonify ({"success" : False , "message" : "Unauthorized block signer" }), 403
123+
124+ if blockchain .crypto_manager :
125+ if not v_block .signature :
126+ return jsonify ({"success" : False , "message" : "Missing digital signature" }), 400
123127 if not blockchain .crypto_manager .verify_signature (v_block .hash , v_block .signature ):
124128 return jsonify ({"success" : False , "message" : "Invalid digital signature" }), 400
125129
126- # All checks passed, add to local DB and chain
130+ # Finality gate: old blocks may omit status; accepted blocks become FINALIZED.
131+ if v_block .status not in (None , "FINALIZED" ):
132+ return jsonify ({"success" : False , "message" : "Block status must be FINALIZED" }), 400
133+
134+ # 2. Validate against local chain linkage
135+ last_block = blockchain .get_latest_block ()
136+ if last_block and block_data ["index" ] <= last_block .index :
137+ return jsonify ({"success" : True , "message" : "Outdated block ignored" }), 200
138+
139+ if last_block and block_data ["previous_hash" ] != last_block .hash :
140+ return jsonify ({"success" : False , "message" : "Previous hash mismatch. Sync required." }), 400
141+
142+ # 3. Persist only after full validation
143+ new_block = blockchain .block_model (
144+ index = block_data ["index" ],
145+ timestamp = block_data ["timestamp" ],
146+ data = json .dumps (block_data ["data" ]),
147+ merkle_root = block_data .get ("merkle_root" ),
148+ previous_hash = block_data ["previous_hash" ],
149+ nonce = block_data ["nonce" ],
150+ hash = block_data ["hash" ],
151+ signed_by = block_data .get ("signed_by" ),
152+ signature = block_data .get ("signature" ),
153+ )
154+
127155 db .session .add (new_block )
128156 db .session .commit ()
157+ v_block .status = "FINALIZED"
129158 blockchain .chain .append (v_block )
130159
131- logging .info (f"Accepted peer block { block_data ['index' ]} from { block_data .get ('signed_by' )} " )
160+ # Controlled gossip propagation: relay accepted blocks, never back to sender.
161+ blockchain .broadcast_block (v_block , source_node = source_node , origin_node = origin_node )
162+
163+ logging .info (
164+ f"Accepted peer block { block_data ['index' ]} from signer={ block_data .get ('signed_by' )} "
165+ f"source={ source_node or 'unknown' } origin={ origin_node } sender={ sender_node or 'unknown' } "
166+ )
132167 return jsonify ({"success" : True , "message" : "Block accepted and added to chain" })
133168
134169 except Exception as e :
0 commit comments