Diff

Differences From Artifact [d46c2149d2]:

To Artifact [21ddbdd709]:


1738
1739
1740
1741
1742
1743
1744

1745
1746
1747










1748
1749
1750
1751
1752
1753
1754
1738
1739
1740
1741
1742
1743
1744
1745



1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762







+
-
-
-
+
+
+
+
+
+
+
+
+
+







		set basis_node [dict get $basis "node"]
	}
	set default_node [dict create \
		"client_id_private_key"     [::nano::key::newKey] \
		"bootstrap_connections" "4" \
	]

	# Configure based on network
	# XXX:TODO: Consider network
	dict set default_node "peering_port" "7075"
	dict set default_node "preconfigured_peers" [list "rai.raiblocks.net"]
	switch -- $network {
		"main" {
			dict set default_node "peering_port" "7075"
			dict set default_node "preconfigured_peers" [list "rai.raiblocks.net"]
		}
		"beta" {
			dict set default_node "peering_port" "54000"
			dict set default_node "preconfigured_peers" [list "rai-beta.raiblocks.net"]
		}
	}

	catch {
		set basis_node_database [dict create]
		set basis_node_database [dict get $basis "node" "database"]
	}
	set default_node_database [dict create \
		"backend"        "lmdb" \
1779
1780
1781
1782
1783
1784
1785


1786
1787
1788
1789
1790
1791
1792
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802







+
+







	}

	set configuration [::json::json2dict $json]

	set configuration [_defaultConfig $configuration $network]

	set ::nano::node::configuration $configuration

	dict set ::nano::node::configuration network $network

	return $::nano::node::configuration
}

proc ::nano::node::_saveConfigFile {file args} {
	if {[llength $args] == 0} {
		set configDict $::nano::node::configuration
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832











1833
1834
1835
1836
1837
1838
1839
1831
1832
1833
1834
1835
1836
1837





1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855







-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+







}

proc ::nano::node::configure {network args} {
	package require ip
	package require dns

	# Set default options
	## XXX:TODO: Handle other networks
	if {$network ne "main"} {
		return -code error "Only main network is supported right now"
	}
	set info(-configDirectory) [file normalize ~/RaiBlocks]
	switch -- $network {
		"main" {
			set info(-configDirectory) [file normalize ~/RaiBlocks]
		}
		"beta" {
			set info(-configDirectory) [file normalize ~/RaiBlocksBeta]
		}
		default {
			return -code error "Only main, and beta networks are supported right now"
		}
	}

	# Parse options to the configure
	array set info $args

	# Load configuration file
	set configFile [file join $info(-configDirectory) "config.json"]

2088
2089
2090
2091
2092
2093
2094
2095



2096
2097
2098
2099
2100
2101
2102
2104
2105
2106
2107
2108
2109
2110

2111
2112
2113
2114
2115
2116
2117
2118
2119
2120







-
+
+
+








		return -code error "Invalid type specified: $type"
	}

	if {"query" in $types} {
		::nano::protocol::extensions::set "node_id_handshake" extensions "query"

		# XXX:TODO: Verify this is exactly a 32-byte nonce
		if {[string length $argInfo(-query)] != 32} {
			return -code error "Invalid input data"
		}

		append data $argInfo(-query)
	}

	if {"response" in $types} {
		::nano::protocol::extensions::set "node_id_handshake" extensions "response"

2219
2220
2221
2222
2223
2224
2225

2226
2227
2228
2229
2230
2231
2232

2233
2234
2235
2236
2237
2238
2239
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259







+







+







	return [array get retval]
}

proc ::nano::protocol::parse::confirm_req {extensions blockData} {
	set blockTypeID [expr {($extensions >> 8) & 0x0f}]
	set blockType [::nano::block::typeFromTypeID $blockTypeID]
	set blockDict [::nano::block::dict::fromBlock $blockData -type=$blockType]
	set blockHash [::nano::block::dict::toHash $blockDict -hex]

	# XXX:TEMPORARY
	dict unset blockDict _blockData
	dict unset blockDict _workData

	set retval(blockType) $blockType
	set retval(block) $blockDict
	set retval(hash) $blockHash

	return [array get retval]
}

proc ::nano::protocol::parse::confirm_ack {extensions blockData} {
	set blockTypeID [expr {($extensions >> 8) & 0x0f}]
	set blockType [::nano::block::typeFromTypeID $blockTypeID]
2316
2317
2318
2319
2320
2321
2322
2323

2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339









2340
2341

2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355


2356

2357
2358
2359
2360
2361
2362
2363
2336
2337
2338
2339
2340
2341
2342

2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369

2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386

2387
2388
2389
2390
2391
2392
2393
2394







-
+
















+
+
+
+
+
+
+
+
+

-
+














+
+
-
+







	} else {
		set retval(valid) true
	}

	return [array get retval]
}

proc ::nano::protocol::create {messageType args} {
proc ::nano::protocol::create {network messageType args} {
	set versionUsing 14
	set versionMin 13
	set versionMax $versionUsing
	set messageInfo(extensions) 0
	set messageInfo(blockType) 0

	set messageType [string tolower $messageType]
	set messageTypeID [lsearch -exact $::nano::network::messageTypes $messageType]
	if {$messageTypeID == -1} {
		return -code error "Invalid message type: $messageType"
	}

	array set messageInfo [::nano::protocol::create::${messageType} {*}$args]

	set messageInfo(extensions) [expr {$messageInfo(extensions) | (($messageInfo(blockType) << 8) & 0x0f00)}]

	switch -- $network {
		"main" {
			set packetMagic "RC"
		}
		"beta" {
			set packetMagic "RB"
		}
	}

	set message [binary format a2ccccs \
		RC \
		$packetMagic \
		$versionMax \
		$versionUsing \
		$versionMin \
		$messageTypeID \
		$messageInfo(extensions) \
	]

	append message $messageInfo(data)

	return $message
}


proc ::nano::network::client {sock messageType args} {
	set configuredNetwork [dict get $::nano::node::configuration network]

	set message [::nano::protocol::create $messageType {*}$args]
	set message [::nano::protocol::create $configuredNetwork $messageType {*}$args]

	::nano::node::log "Sending message [binary encode hex $message] ([::nano::protocol::parse $message]) to socket $sock"

	catch {
		if {[dict get $sock "type"] eq "realtime"} {
			set sockInfo $sock
			set sock [dict get $sock "socket"]
2848
2849
2850
2851
2852
2853
2854



2855
2856
2857
2858
2859
2860
2861
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895







+
+
+







		return ""
	}

	switch -- $result(packetMagic) {
		"RC" {
			set result(network) "main"
		}
		"RB" {
			set result(network) "beta"
		}
		default {
			return ""
		}
	}

	set result(messageType) [lindex $::nano::network::messageTypes $result(messageTypeID)]

2875
2876
2877
2878
2879
2880
2881





2882
2883
2884
2885
2886
2887
2888
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927







+
+
+
+
+







	dict with messageData {}

	::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} {
		return ""
	}

	dict set messageDict socket $peerSock

	set retval [dict create]
	if {[catch {
		set retval [::nano::network::server::${messageType} $messageDict]
	} err]} {
2963
2964
2965
2966
2967
2968
2969







2970
2971
2972
2973
2974
2975
2976







2977
2978




2979
2980
2981
2982
2983


2984


2985
2986
2987
2988
2989
2990
2991
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015







3016
3017
3018
3019
3020
3021
3022
3023

3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034

3035
3036
3037
3038
3039
3040
3041
3042
3043







+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+

-
+
+
+
+





+
+
-
+
+







	# Start listening
	::nano::node::socket realtime "" ""

	# Periodically send keepalives to all known peers
	while true {
		set allPeers [::nano::node::getPeers]
		set peers [lrange $allPeers 0 15]

		# XXX:TODO: Make this a configuration option
		set superPeer true

		if {$superPeer} {
			set contactPeers $allPeers
		} else {
		set peerNotifyCount [expr {int(sqrt([llength $allPeers]))}]
		if {$peerNotifyCount < 16} {
			set peerNotifyCount 16
		}
		if {$peerNotifyCount > 128} {
			set peerNotifyCount 128
		}
			set peerNotifyCount [expr {int(sqrt([llength $allPeers]))}]
			if {$peerNotifyCount < 16} {
				set peerNotifyCount 16
			}
			if {$peerNotifyCount > 128} {
				set peerNotifyCount 128
			}

		foreach peerInfo [lrange $allPeers 0 $peerNotifyCount] {
			set contactPeers [lrange $allPeers 0 $peerNotifyCount]
		}

		foreach peerInfo $contactPeers {
			set peerAddress [dict get $peerInfo "address"]
			set peerPort [dict get $peerInfo "port"]

			set peerSock [::nano::node::socket realtime $peerAddress $peerPort]

			set node_id_nonce [::nano::internal::randomBytes 32]

			::nano::network::client $peerSock "keepalive" $peers -local true
			::nano::network::client $peerSock keepalive $peers -local true
			::nano::network::client $peerSock node_id_handshake query -query $node_id_nonce
		}

		::nano::node::_sleep [expr {1 * 60 * 1000}]
	}
}

proc ::nano::node::start args {