Diff

Differences From Artifact [f990275d18]:

To Artifact [ecb41a3def]:


309
310
311
312
313
314
315
316
317
318
319
320
321
322
323

# Low-level block management
proc ::nano::block::dict::toBlock {blockDict} {
	array set block $blockDict

	switch -- $block(type) {
		"state" {
			append blockData $::nano::block::stateBlockPreamble
			append blockData [::nano::address::toPublicKey $block(account)]
			append blockData [binary decode hex $block(previous)]
			append blockData [::nano::address::toPublicKey $block(representative)]
			append blockData [binary decode hex [format %032llX $block(balance)]]
			if {![info exists block(link)] && [info exists block(link_as_account)]} {
				append blockData [::nano::address::toPublicKey $block(link_as_account)]
			} else {







<







309
310
311
312
313
314
315

316
317
318
319
320
321
322

# Low-level block management
proc ::nano::block::dict::toBlock {blockDict} {
	array set block $blockDict

	switch -- $block(type) {
		"state" {

			append blockData [::nano::address::toPublicKey $block(account)]
			append blockData [binary decode hex $block(previous)]
			append blockData [::nano::address::toPublicKey $block(representative)]
			append blockData [binary decode hex [format %032llX $block(balance)]]
			if {![info exists block(link)] && [info exists block(link_as_account)]} {
				append blockData [::nano::address::toPublicKey $block(link_as_account)]
			} else {
461
462
463
464
465
466
467
468































































































































































469

470
471
472
473
474
475
476
	}]
	set blockJSONEntries [join $blockJSONEntries]

	set blockJSON [json::write object {*}$blockJSONEntries]

	return $blockJSON
}
































































































































































proc ::nano::block::dict::fromBlock {blockData args} {

	set block(type) ""
	set addressPrefix "nano_"
	foreach arg $args {
		switch -glob -- $arg {
			"-type=*" {
				set block(type) [lindex [split $arg =] 1]
			}








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
	}]
	set blockJSONEntries [join $blockJSONEntries]

	set blockJSON [json::write object {*}$blockJSONEntries]

	return $blockJSON
}

proc ::nano::block::typeIDFromType {type} {
	set outputFormat decimal
	foreach arg $args {
		switch -exact -- $arg {
			"-dec" - "-decimal" {
				set outputFormat "decimal"
			}
			"-hex" {
				set outputFormat "hex"
			}
			"-binary" {
				set outputFormat "bytes"
			}
			default {
				return -code error "Invalid option: $arg"
			}
		}
	}

	switch -- $type {
		"invalid"     { set typeId 0 }
		"not_a_block" { set typeId 1 }
		"send"        { set typeId 2 }
		"receive"     { set typeId 3 }
		"open"        { set typeId 4 }
		"change"      { set typeId 5 }
		"state"       { set typeId 6 }
	}

	switch -- $outputFormat {
		"decimal" {
			set result $typeId
		}
		"hex" {
			set result [format %02x $typeId]
		}
		"bytes" {
			set result [binary decode hex [format %02x $typeId]]
		}
	}

	return $result
}

proc ::nano::block::typeFromTypeID {typeId args} {
	set inputFormat decimal
	foreach arg $args {
		switch -exact -- $arg {
			"-dec" - "-decimal" {
				set inputFormat "decimal"
			}
			"-hex" {
				set inputFormat "hex"
			}
			"-binary" {
				set inputFormat "bytes"
			}
			default {
				return -code error "Invalid option: $arg"
			}
		}
	}

	switch -- $inputFormat {
		"decimal" { }
		"hex" {
			if {![string match "0x*" $typeId]} {
				set typeId "0x${typeId}"
			}
		}
		"bytes" {
			set typeId [binary encode hex $typeId]
			set typeId "0x${typeId}"
		}
	}

	switch -- [format %i $typeId] {
		0 { set type "invalid" }
		1 { set type "not_a_block" }
		2 { set type "send" }
		3 { set type "receive" }
		4 { set type "open" }
		5 { set type "change" }
		6 { set type "state" }
	}

	return $type
}

proc ::nano::block::lengthFromType {type args} {
	set includeType false
	set includeWork false
	set includeSig  false
	foreach arg $args {
		switch -exact -- $arg {
			"-full" {
				set includeType true
				set includeWork true
				set includeSig  true
			}
			"-work" {
				set includeWork true
			}
			"-signature" {
				set includeSig  true
			}
			"-type" {
				set includeType true
			}
			default {
				return -code error "Invalid option: $arg"
			}
		}
	}

	switch -- $type {
		"invalid" - "not_a_block" {
			set length 0
			set includeWork false
			set includeSig false
		}
		"state"   { set length 144 }
		"open"    { set length 96  }
		"send"    { set length 80  }
		"receive" { set length 64  }
		"change"  { set length 64  }
		default {
			return -code error "Unknown type: $type"
		}
	}

	if {$includeType} {
		incr length
	}

	if {$includeWork} {
		incr length 8
	}

	if {$includeSig} {
		incr length 64
	}

	return $length
}

proc ::nano::block::typeFromLength {length} {
	switch -- $length {
		144 { set type state }
		96  { set type open  }
		80  { set type send  }
		default {
			return -code error "Ambigious"
		}
	}

	return $type
}

proc ::nano::block::dict::fromBlock {blockData args} {
	set block(_blockData) $blockData
	set block(type) ""
	set addressPrefix "nano_"
	foreach arg $args {
		switch -glob -- $arg {
			"-type=*" {
				set block(type) [lindex [split $arg =] 1]
			}
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525


526
527
528
529
530
531
532
533


534
535
536
537
538
539
540


541
542
543
544
545
546
547


548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
			}
			default {
			}
		}
	}

	if {$block(type) eq ""} {
		switch -- [string length $blockData] {
			176 { set block(type) state   }
			96  { set block(type) open    }
			80  { set block(type) send    }
			default {
				return -code error "Unable to parse block, must specify type"
			}
		}
	}

	set addArgs_fromPublicKey [list]
	if {$addressPrefix eq "xrb_"} {
		lappend addArgs_fromPublicKey "-xrb"
	}

	switch -- $block(type) {
		"state" {
			binary scan $blockData a32a32H64a32H32H64 \
				block(header) \
				block(account) \
				block(previous) \
				block(representative) \
				block(balance) \
				block(link)

			if {$block(header) ne $::nano::block::stateBlockPreamble} {
				return -code error "Invalid block"
			}
		}
		"open" {
			binary scan $blockData H64a32a32 \
				block(source) \
				block(representative) \
				block(account)



			set block(_workData) $block(account)
		}
		"send" {
			binary scan $blockData H64a32H32 \
				block(previous) \
				block(destination) \
				block(balance)



			set block(_workData) $block(previous)
		}
		"receive" {
			binary scan $blockData H64H64 \
				block(previous) \
				block(source)



			set block(_workData) $block(previous)
		}
		"change" {
			binary scan $blockData H64a32 \
				block(previous) \
				block(representative)



			set block(_workData) $block(previous)
		}
		default {
			return -code error "Invalid block type: $block(type)"
		}
	}

	foreach field {account representative link_as_account destination balance} {
		if {![info exists block($field)]} {
			continue
		}

		switch -exact -- $field {
			"account" - "representative" - "link_as_account" - "destination" {
				set block($field) [::nano::address::fromPublicKey $block($field) {*}$addArgs_fromPublicKey]
			}
			"balance" {
				set block($field) [format %lli "0x$block($field)"]
			}
		}
	}

	set block(_blockData) $blockData

	return [array get block]
}

proc ::nano::block::json::fromBlock {blockData args} {
	set blockDict [::nano::block::dict::fromBlock $blockData {*}$args]

	set blockJSON [::nano::block::json::fromDict $blockDict]

	return $blockJSON
}

proc ::nano::block::hash {blockData args} {
	set outputFormat "bytes"
	foreach arg $args {
		switch -exact -- $arg {
			"-hex" {
				set outputFormat "hex"
			}
			"-binary" {







|
|
<
<
|
|
<










|
<




|
|
<
|
|
<

|


|
>
>




|


|
>
>




|

|
>
>




|

|
>
>








|














<












|







644
645
646
647
648
649
650
651
652


653
654

655
656
657
658
659
660
661
662
663
664
665

666
667
668
669
670
671

672
673

674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731

732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
			}
			default {
			}
		}
	}

	if {$block(type) eq ""} {
		if {[catch {
			set block(type) [::nano::block::typeFromLength [string length $blockData]]


		}]} {
			return -code error "Unable to parse block, must specify type"

		}
	}

	set addArgs_fromPublicKey [list]
	if {$addressPrefix eq "xrb_"} {
		lappend addArgs_fromPublicKey "-xrb"
	}

	switch -- $block(type) {
		"state" {
			binary scan $blockData a32H64a32H32H64H128H16 \

				block(account) \
				block(previous) \
				block(representative) \
				block(balance) \
				block(link) \
				block(signature) \

				block(work)
		}

		"open" {
			binary scan $blockData H64a32a32H128H16 \
				block(source) \
				block(representative) \
				block(account) \
				block(signature) \
				block(work)

			set block(_workData) $block(account)
		}
		"send" {
			binary scan $blockData H64a32H32H128H16 \
				block(previous) \
				block(destination) \
				block(balance) \
				block(signature) \
				block(work)

			set block(_workData) $block(previous)
		}
		"receive" {
			binary scan $blockData H64H64H128H16 \
				block(previous) \
				block(source) \
				block(signature) \
				block(work)

			set block(_workData) $block(previous)
		}
		"change" {
			binary scan $blockData H64a32H128H16 \
				block(previous) \
				block(representative) \
				block(signature) \
				block(work)

			set block(_workData) $block(previous)
		}
		default {
			return -code error "Invalid block type: $block(type)"
		}
	}

	foreach field {account representative link_as_account destination balance work signature} {
		if {![info exists block($field)]} {
			continue
		}

		switch -exact -- $field {
			"account" - "representative" - "link_as_account" - "destination" {
				set block($field) [::nano::address::fromPublicKey $block($field) {*}$addArgs_fromPublicKey]
			}
			"balance" {
				set block($field) [format %lli "0x$block($field)"]
			}
		}
	}



	return [array get block]
}

proc ::nano::block::json::fromBlock {blockData args} {
	set blockDict [::nano::block::dict::fromBlock $blockData {*}$args]

	set blockJSON [::nano::block::json::fromDict $blockDict]

	return $blockJSON
}

proc ::nano::block::_hash {blockData args} {
	set outputFormat "bytes"
	foreach arg $args {
		switch -exact -- $arg {
			"-hex" {
				set outputFormat "hex"
			}
			"-binary" {
601
602
603
604
605
606
607
















608
609
610
611
612
613
614

	if {$outputFormat eq "hex"} {
		set hash [string toupper [binary encode hex $hash]]
	}

	return $hash
}

















proc ::nano::block::signBlockHash {blockHash privateKey args} {
	set outputFormat "bytes"
	foreach arg $args {
		switch -exact -- $arg {
			"-hex" {
				set outputFormat "hex"







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790

	if {$outputFormat eq "hex"} {
		set hash [string toupper [binary encode hex $hash]]
	}

	return $hash
}

proc ::nano::block::dict::toHash {blockDict args} {
	if {[dict get $blockDict type] eq "state"} {
		set blockData $::nano::block::stateBlockPreamble
	}

	append blockData [::nano::block::dict::toBlock $blockDict]

	tailcall ::nano::block::_hash $blockData {*}$args
}

proc ::nano::block::json::toHash {blockJSON args} {
	set blockDict [::nano::block::dict::fromJSON $blockJSON]

	tailcall ::nano::block::dict::toHash $blockDict {*}$args
}

proc ::nano::block::signBlockHash {blockHash privateKey args} {
	set outputFormat "bytes"
	foreach arg $args {
		switch -exact -- $arg {
			"-hex" {
				set outputFormat "hex"
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
	if {$outputFormat eq "hex"} {
		set signature [string toupper [binary encode hex $signature]]
	}

	return $signature
}

proc ::nano::block::sign {blockData args} {
	set blockHash [::nano::block::hash $blockData]

	tailcall ::nano::block::signBlockHash $blockHash {*}$args
}

proc ::nano::block::verifyBlockHash {blockHash signature publicKey} {
	if {[string length $blockHash] != $::nano::block::hashLength} {
		set blockHash [binary decode hex $blockHash]







|
|







811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
	if {$outputFormat eq "hex"} {
		set signature [string toupper [binary encode hex $signature]]
	}

	return $signature
}

proc ::nano::block::_sign {blockData args} {
	set blockHash [::nano::block::_hash $blockData]

	tailcall ::nano::block::signBlockHash $blockHash {*}$args
}

proc ::nano::block::verifyBlockHash {blockHash signature publicKey} {
	if {[string length $blockHash] != $::nano::block::hashLength} {
		set blockHash [binary decode hex $blockHash]
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
	}

	set valid [::nano::internal::verifyDetached $blockHash $signature $publicKey]

	return $valid
}

proc ::nano::block::verifyBlock {blockData args} {
	set blockHash [::nano::block::hash $blockData]

	tailcall ::nano::block::verifyBlockHash $blockHash {*}$args
}

proc ::nano::block::dict::_addBlockData {blockDict} {
	if {[dict exists $blockDict _blockData]} {
		return $blockDict







|
|







835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
	}

	set valid [::nano::internal::verifyDetached $blockHash $signature $publicKey]

	return $valid
}

proc ::nano::block::_verifyBlock {blockData args} {
	set blockHash [::nano::block::_hash $blockData]

	tailcall ::nano::block::verifyBlockHash $blockHash {*}$args
}

proc ::nano::block::dict::_addBlockData {blockDict} {
	if {[dict exists $blockDict _blockData]} {
		return $blockDict
685
686
687
688
689
690
691




692
693
694
695
696
697
698
699
	if {[dict exists $blockDict _blockHash]} {
		return $blockDict
	}

	set blockDict [_addBlockData $blockDict]
	set blockData [dict get $blockDict _blockData]





	set blockHash [::nano::block::hash $blockData -binary]

	dict set blockDict _blockHash $blockHash

	return $blockDict
}

proc ::nano::block::dict::sign {blockDict privateKey args} {







>
>
>
>
|







861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
	if {[dict exists $blockDict _blockHash]} {
		return $blockDict
	}

	set blockDict [_addBlockData $blockDict]
	set blockData [dict get $blockDict _blockData]

	if {[dict get $blockDict type] eq "state"} {
		set blockData "${::nano::block::stateBlockPreamble}${blockData}"
	}

	set blockHash [::nano::block::_hash $blockData -binary]

	dict set blockDict _blockHash $blockHash

	return $blockDict
}

proc ::nano::block::dict::sign {blockDict privateKey args} {
1625
1626
1627
1628
1629
1630
1631



1632
1633
1634
1635
1636
1637
1638

	foreach proc $procs {
		proc ::nano::node::ledger::$proc args [concat [list tailcall {*}$handle $proc] {{*}$args}]
	}
}

proc ::nano::node::configure {network args} {



	# 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]








>
>
>







1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821

	foreach proc $procs {
		proc ::nano::node::ledger::$proc args [concat [list tailcall {*}$handle $proc] {{*}$args}]
	}
}

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]

1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
		}
	}

	return [string range $retval 0 143]
}

proc ::nano::network::client {sock messageType args} {
	set versionUsing 12
	set versionMin 1
	set versionMax 12
	set extensions 0

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







|
|
|







2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
		}
	}

	return [string range $retval 0 143]
}

proc ::nano::network::client {sock messageType args} {
	set versionUsing 7
	set versionMin 7
	set versionMax 7
	set extensions 0

	set messageType [string tolower $messageType]
	set messageTypeID [lsearch -exact $::nano::network::messageTypes $messageType]
	if {$messageTypeID == -1} {
		return -code error "Invalid message type: $messageType"
	}
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
	if {$packetMagic ne "RC"} {
		return ""
	}

	# XXX:TODO: Check versions and extensions

	set messageType [lindex $::nano::network::messageTypes $messageTypeID]
puts "*** Incoming: $messageType ($messageTypeID on $networkType) [binary encode hex $message]"

	set retval ""
	if {[catch {
		set retval [::nano::node::server::${messageType} $args]
	} err]} {
		if {![string match "invalid command name *" $err]} {
			::nano::node::log "Error handling ${messageType}: $err"







|







2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
	if {$packetMagic ne "RC"} {
		return ""
	}

	# XXX:TODO: Check versions and extensions

	set messageType [lindex $::nano::network::messageTypes $messageTypeID]
#puts "*** Incoming: $messageType ($messageTypeID on $networkType) [binary encode hex $message]"

	set retval ""
	if {[catch {
		set retval [::nano::node::server::${messageType} $args]
	} err]} {
		if {![string match "invalid command name *" $err]} {
			::nano::node::log "Error handling ${messageType}: $err"
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384

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

proc ::nano::node::start {} {
	package require defer
	package require ip
	package require udp
	package require dns

	coroutine ::nano::node::bootstrap::run ::nano::node::bootstrap
	coroutine ::nano::node::realtime::run ::nano::node::realtime

	vwait ::nano::node::_FOREVER_
}








<

<







2551
2552
2553
2554
2555
2556
2557

2558

2559
2560
2561
2562
2563
2564
2565

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

proc ::nano::node::start {} {
	package require defer

	package require udp


	coroutine ::nano::node::bootstrap::run ::nano::node::bootstrap
	coroutine ::nano::node::realtime::run ::nano::node::realtime

	vwait ::nano::node::_FOREVER_
}