Check-in [995dbd8993]
Overview
Comment:Better peer tracking and block verification
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 995dbd8993b43b8b63eb8750b7e9a0db15e1297b4005eb66c7d53031f8abd42a
User & Date: rkeene on 2019-01-22 17:51:51
Other Links: manifest | tags
Context
2019-01-22
17:55
Check to see if -mmpx can actually be linked in check-in: ad21e0c8c7 user: rkeene tags: trunk
17:51
Better peer tracking and block verification check-in: 995dbd8993 user: rkeene tags: trunk
17:47
Updated kit building check-in: 572ef3e921 user: rkeene tags: trunk
Changes

Modified nano.tcl from [42c9c4c386] to [62c2803e15].

204
205
206
207
208
209
210




211
212
213
214
215
216
217
				return -code error "Invalid option: $arg"
			}
		}
	}

	if {[string length $publicKey] != $::nano::key::publicKeyLength} {
		set publicKey [binary decode hex $publicKey]




	}

	set checksum [string reverse [::nano::internal::hashData $publicKey 5]]
	append publicKey $checksum

	set publicKey [binary encode hex $publicKey]
	set publicKey [expr "0x$publicKey"]







>
>
>
>







204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
				return -code error "Invalid option: $arg"
			}
		}
	}

	if {[string length $publicKey] != $::nano::key::publicKeyLength} {
		set publicKey [binary decode hex $publicKey]

		if {[string length $publicKey] != $::nano::key::publicKeyLength} {
			return -code error "Invalid public key (length: [string length $publicKey], expected $::nano::key::publicKeyLength)"
		}
	}

	set checksum [string reverse [::nano::internal::hashData $publicKey 5]]
	append publicKey $checksum

	set publicKey [binary encode hex $publicKey]
	set publicKey [expr "0x$publicKey"]
455
456
457
458
459
460
461







462
463
464
465
466
467
468
	if {[info exists workDataBasedOn]} {
		if {$workDataBasedOn eq "previous"} {
			dict set blockDict "_workData" [dict get $blockDict "previous"]
		} else {
			dict set blockDict "_workData" [::nano::address::toPublicKey [dict get $blockDict "account"]]
		}
	}








	return $blockDict
}

proc ::nano::block::dict::fromJSON {blockJSON} {
	set retval [::json::json2dict $blockJSON]








>
>
>
>
>
>
>







459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
	if {[info exists workDataBasedOn]} {
		if {$workDataBasedOn eq "previous"} {
			dict set blockDict "_workData" [dict get $blockDict "previous"]
		} else {
			dict set blockDict "_workData" [::nano::address::toPublicKey [dict get $blockDict "account"]]
		}
	}

	if {[dict exists $blockDict "work"]} {
		set valid [::nano::work::validate [dict get $blockDict "_workData"] [dict get $blockDict "work"]]
		if {!$valid} {
			return -code error "Invalid work when adding block"
		}
	}

	return $blockDict
}

proc ::nano::block::dict::fromJSON {blockJSON} {
	set retval [::json::json2dict $blockJSON]

3256
3257
3258
3259
3260
3261
3262




3263
3264
3265
3266
3267
3268
3269
3270




3271
3272
3273
3274
3275
3276
3277
			}
		}
	}

	set now [clock seconds]
	# Cleanup nonces while we are here
	foreach {peerKey peerInfo} [array get ::nano::node::_node_id_nonces] {




		set lastSeen [dict get $peerInfo "lastSeen"]
		if {($now - $lastSeen) > (5 * 60)} {
			unset ::nano::node::_node_id_nonces($peerKey)
		}
	}

	# Come up with a list of peers that we have seen recently
	foreach {peerKeyInfo peerInfo} [array get ::nano::node::peers] {




		set lastSeen [dict get $peerInfo "lastSeen"]
		set address [dict get $peerKeyInfo "address"]
		set peerPort [dict get $peerKeyInfo "port"]
		set peerKey [dict create address $address port $peerPort]

		if {($now - $lastSeen) > (5 * 60)} {
#puts "Have not seen $peerKey in a while, dropping (now=$now, lastSeen=$lastSeen)"







>
>
>
>








>
>
>
>







3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
			}
		}
	}

	set now [clock seconds]
	# Cleanup nonces while we are here
	foreach {peerKey peerInfo} [array get ::nano::node::_node_id_nonces] {
		if {![dict exists $peerInfo "lastSeen"]} {
			continue
		}

		set lastSeen [dict get $peerInfo "lastSeen"]
		if {($now - $lastSeen) > (5 * 60)} {
			unset ::nano::node::_node_id_nonces($peerKey)
		}
	}

	# Come up with a list of peers that we have seen recently
	foreach {peerKeyInfo peerInfo} [array get ::nano::node::peers] {
		if {![dict exists $peerInfo "lastSeen"]} {
			continue
		}

		set lastSeen [dict get $peerInfo "lastSeen"]
		set address [dict get $peerKeyInfo "address"]
		set peerPort [dict get $peerKeyInfo "port"]
		set peerKey [dict create address $address port $peerPort]

		if {($now - $lastSeen) > (5 * 60)} {
#puts "Have not seen $peerKey in a while, dropping (now=$now, lastSeen=$lastSeen)"
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
		# If this peer is not already known, contact them requesting a handshake
		if {![info exists ::nano::node::peers($peer)]} {
			if {![info exists ::nano::node::_node_id_nonces($peer)]} {
				set node_id_nonce [::nano::internal::randomBytes 32]
				set ::nano::node::_node_id_nonces($peer) [dict create query $node_id_nonce lastSeen $now]

				set peerSock [::nano::node::createSocket realtime $address $port]
#puts "Querying $peerSock with node_id_handshake (1)"
				::nano::network::client $peerSock "node_id_handshake" query -query $node_id_nonce
			}
		}
	}

	# Stats
	::nano::node::stats::incr [list keepalive]







<







3356
3357
3358
3359
3360
3361
3362

3363
3364
3365
3366
3367
3368
3369
		# If this peer is not already known, contact them requesting a handshake
		if {![info exists ::nano::node::peers($peer)]} {
			if {![info exists ::nano::node::_node_id_nonces($peer)]} {
				set node_id_nonce [::nano::internal::randomBytes 32]
				set ::nano::node::_node_id_nonces($peer) [dict create query $node_id_nonce lastSeen $now]

				set peerSock [::nano::node::createSocket realtime $address $port]

				::nano::network::client $peerSock "node_id_handshake" query -query $node_id_nonce
			}
		}
	}

	# Stats
	::nano::node::stats::incr [list keepalive]
3369
3370
3371
3372
3373
3374
3375








3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413

	if {"response" in $flags} {
		binary scan $messageData H64H128 result(key) result(signature)
	}

	return [array get result]
}









proc ::nano::network::server::node_id_handshake {messageDict} {
	set retval ""

	::nano::node::stats::incr [list node_id_handshake]

	if {"query" in [dict get $messageDict flags]} {
		set query [dict get $messageDict query]
		set clientID [dict get $::nano::node::configuration node client_id_private_key]
		set retval [dict create "invoke_client" [list node_id_handshake response -privateKey $clientID -query [binary decode hex $query]]]

		# Stats
		::nano::node::stats::incr [list node_id_handshake query]
	}

	if {"response" in [dict get $messageDict flags]} {
		set peerInfo [dict get $messageDict socket remote]
		set peerAddress [lindex $peerInfo 0]
		set peerPort [lindex $peerInfo 1]
		set peer [dict create address $peerAddress port $peerPort]

		# XXX:TODO: Verify the nonce
		if {![info exists ::nano::node::_node_id_nonces($peer)]} {
			return ""
		}
		set sentNonce $::nano::node::_node_id_nonces($peer)
		unset ::nano::node::_node_id_nonces($peer)

		# Add the peer to our list of peers
#puts "Got node_id_handshake response from $peer"
		set ::nano::node::peers($peer) [dict create lastSeen [clock seconds]]

		# Stats
		::nano::node::stats::incr [list node_id_handshake response]
		::nano::node::stats::lappend [list node_id_handshake response uniqueKeys] [dict get $messageDict key]
	}

	return $retval







>
>
>
>
>
>
>
>
















|
<
<
<









|
|







3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418



3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436

	if {"response" in $flags} {
		binary scan $messageData H64H128 result(key) result(signature)
	}

	return [array get result]
}

proc ::nano::network::_socketToPeer {realtimeSocket} {
	set peerInfo [dict get $realtimeSocket remote]
	set peerAddress [lindex $peerInfo 0]
	set peerPort [lindex $peerInfo 1]
	set peer [dict create address $peerAddress port $peerPort]
	return $peer
}

proc ::nano::network::server::node_id_handshake {messageDict} {
	set retval ""

	::nano::node::stats::incr [list node_id_handshake]

	if {"query" in [dict get $messageDict flags]} {
		set query [dict get $messageDict query]
		set clientID [dict get $::nano::node::configuration node client_id_private_key]
		set retval [dict create "invoke_client" [list node_id_handshake response -privateKey $clientID -query [binary decode hex $query]]]

		# Stats
		::nano::node::stats::incr [list node_id_handshake query]
	}

	if {"response" in [dict get $messageDict flags]} {
		set peer [::nano::network::_socketToPeer [dict get $messageDict socket]]




		# XXX:TODO: Verify the nonce
		if {![info exists ::nano::node::_node_id_nonces($peer)]} {
			return ""
		}
		set sentNonce $::nano::node::_node_id_nonces($peer)
		unset ::nano::node::_node_id_nonces($peer)

		# Add the peer to our list of peers
		dict set ::nano::node::peers($peer) lastSeen [clock seconds]
		dict set ::nano::node::peers($peer) nodeIdKey [dict get $messageDict key]

		# Stats
		::nano::node::stats::incr [list node_id_handshake response]
		::nano::node::stats::lappend [list node_id_handshake response uniqueKeys] [dict get $messageDict key]
	}

	return $retval
3556
3557
3558
3559
3560
3561
3562






3563
3564
3565
3566
3567
3568
3569
	if {![info exists messageTypeID]} {
		::nano::node::log "*** Incoming: INVALID [binary encode hex $message] ($messageData)"

		return ""
	}

	::nano::node::log "*** Incoming: $messageType ($messageTypeID on $networkType; from $peerSock) [binary encode hex $message] ($messageData)"







	if {![info exists messageDict]} {
		return ""
	}

	set configuredNetwork [dict get $::nano::node::configuration network]
	if {$network ne $configuredNetwork} {







>
>
>
>
>
>







3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
	if {![info exists messageTypeID]} {
		::nano::node::log "*** Incoming: INVALID [binary encode hex $message] ($messageData)"

		return ""
	}

	::nano::node::log "*** Incoming: $messageType ($messageTypeID on $networkType; from $peerSock) [binary encode hex $message] ($messageData)"

	catch {
		set peer [::nano::network::_socketToPeer $peerSock]
		dict set ::nano::node::peers($peer) lastPacket [clock seconds]
		dict set ::nano::node::peers($peer) lastVersion $versionUsing
	}

	if {![info exists messageDict]} {
		return ""
	}

	set configuredNetwork [dict get $::nano::node::configuration network]
	if {$network ne $configuredNetwork} {
4377
4378
4379
4380
4381
4382
4383


4384
4385



4386
4387





4388
4389
4390


4391














4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
	foreach peer [::nano::node::getPeers] {
		if {[info exists glob]} {
			if {![string match $glob $peer] == !$globInvert} {
				continue
			}
		}



		if {[info exists ::nano::node::peers($peer)]} {
			set peerInfo $::nano::node::peers($peer)



			set lastSeen [dict get $peerInfo lastSeen]






			set delta [expr {$now - $lastSeen}]

			set age "last seen $delta seconds ago"


		} else {














			set age "statically configured peer"
		}

		lappend response "  $peer: $age"
	}
	return [join $response "\n"]
}

proc ::nano::node::cli::_pull_chain {startBlockHash {endBlockHash "genesis"}} {
	if {$endBlockHash eq "genesis"} {
		set network [dict get $::nano::node::configuration network]







>
>


>
>
>
|

>
>
>
>
>



>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|


|







4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
	foreach peer [::nano::node::getPeers] {
		if {[info exists glob]} {
			if {![string match $glob $peer] == !$globInvert} {
				continue
			}
		}

		unset -nocomplain peerInfo
		set fields [list]
		if {[info exists ::nano::node::peers($peer)]} {
			set peerInfo $::nano::node::peers($peer)
		}

		catch {
			set versionUsing [dict get $peerInfo lastVersion]

			lappend fields "protocol $versionUsing"
		}

		catch {
			set lastSeen [dict get $peerInfo lastSeen]
			set delta [expr {$now - $lastSeen}]

			set age "last seen $delta seconds ago"
			lappend fields $age
		}

		catch {
			set lastPacket [dict get $peerInfo lastPacket]
			set delta [expr {$now - $lastPacket}]

			lappend fields "last packet $delta seconds ago"
		}

		catch {
			set nodeID [dict get $peerInfo nodeIdKey]

			lappend fields "node identifier $nodeID"
		}

		if {[llength $fields] == 0} {
			lappend fields "statically configured peer"
		}

		lappend response "  $peer: [join $fields {, }]"
	}
	return [join $response "\n"]
}

proc ::nano::node::cli::_pull_chain {startBlockHash {endBlockHash "genesis"}} {
	if {$endBlockHash eq "genesis"} {
		set network [dict get $::nano::node::configuration network]