فهرست منبع

Night of the living dead

skoupidi 2 سال پیش
والد
کامیت
16103b84a7
100فایلهای تغییر یافته به همراه955 افزوده شده و 13485 حذف شده
  1. 1 25
      Cargo.lock
  2. 1 3
      Cargo.toml
  3. 3 5
      Makefile
  4. 14 4
      bin/darkfid/Cargo.toml
  5. 16 8
      bin/darkfid/Makefile
  6. 437 47
      bin/darkfid/darkfid_config.toml
  7. 0 0
      bin/darkfid/genesis_block_localnet
  8. 0 0
      bin/darkfid/genesis_block_mainnet
  9. 0 0
      bin/darkfid/genesis_block_testnet
  10. 5 20
      bin/darkfid/src/error.rs
  11. 259 365
      bin/darkfid/src/main.rs
  12. 0 0
      bin/darkfid/src/proto/mod.rs
  13. 0 0
      bin/darkfid/src/proto/protocol_block.rs
  14. 0 0
      bin/darkfid/src/proto/protocol_proposal.rs
  15. 0 0
      bin/darkfid/src/proto/protocol_sync.rs
  16. 0 0
      bin/darkfid/src/proto/protocol_tx.rs
  17. 0 0
      bin/darkfid/src/rpc.rs
  18. 80 41
      bin/darkfid/src/rpc_blockchain.rs
  19. 0 85
      bin/darkfid/src/rpc_misc.rs
  20. 114 58
      bin/darkfid/src/rpc_tx.rs
  21. 0 441
      bin/darkfid/src/rpc_wallet.rs
  22. 2 2
      bin/darkfid/src/task/miner.rs
  23. 0 0
      bin/darkfid/src/task/mod.rs
  24. 0 0
      bin/darkfid/src/task/sync.rs
  25. 0 0
      bin/darkfid/src/tests/forks.rs
  26. 5 8
      bin/darkfid/src/tests/harness.rs
  27. 0 0
      bin/darkfid/src/tests/mod.rs
  28. 0 0
      bin/darkfid/src/utils.rs
  29. 0 44
      bin/darkfid2/Cargo.toml
  30. 0 42
      bin/darkfid2/Makefile
  31. 0 475
      bin/darkfid2/darkfid_config.toml
  32. 0 69
      bin/darkfid2/src/error.rs
  33. 0 419
      bin/darkfid2/src/main.rs
  34. 0 292
      bin/darkfid2/src/rpc_blockchain.rs
  35. 0 220
      bin/darkfid2/src/rpc_tx.rs
  36. 0 1
      contrib/docker/riscv.Dockerfile
  37. 0 1
      contrib/docker/static.Dockerfile
  38. 0 253
      src/consensus/block.rs
  39. 0 206
      src/consensus/clock.rs
  40. 0 6
      src/consensus/consensus_coin.sql
  41. 0 129
      src/consensus/constants.rs
  42. 0 87
      src/consensus/fees.rs
  43. 0 509
      src/consensus/lead_coin.rs
  44. 0 111
      src/consensus/lead_info.rs
  45. 0 78
      src/consensus/mod.rs
  46. 0 33
      src/consensus/proto/mod.rs
  47. 0 134
      src/consensus/proto/protocol_proposal.rs
  48. 0 374
      src/consensus/proto/protocol_sync.rs
  49. 0 206
      src/consensus/proto/protocol_sync_consensus.rs
  50. 0 122
      src/consensus/proto/protocol_tx.rs
  51. 0 95
      src/consensus/rcpt.rs
  52. 0 898
      src/consensus/state.rs
  53. 0 79
      src/consensus/stx.rs
  54. 0 123
      src/consensus/task/block_sync.rs
  55. 0 160
      src/consensus/task/consensus_sync.rs
  56. 0 28
      src/consensus/task/mod.rs
  57. 0 335
      src/consensus/task/proposal.rs
  58. 0 28
      src/consensus/tx.rs
  59. 0 118
      src/consensus/types.rs
  60. 0 111
      src/consensus/utils.rs
  61. 0 1199
      src/consensus/validator.rs
  62. 0 56
      src/consensus/wallet.rs
  63. 0 54
      src/contract/consensus/Cargo.toml
  64. 0 75
      src/contract/consensus/Makefile
  65. 0 66
      src/contract/consensus/proof/consensus_burn_v1.zk
  66. 0 48
      src/contract/consensus/proof/consensus_mint_v1.zk
  67. 0 157
      src/contract/consensus/proof/consensus_proposal_v1.zk
  68. 0 179
      src/contract/consensus/src/client/common.rs
  69. 0 143
      src/contract/consensus/src/client/genesis_stake_v1.rs
  70. 0 44
      src/contract/consensus/src/client/mod.rs
  71. 0 359
      src/contract/consensus/src/client/proposal_v1.rs
  72. 0 117
      src/contract/consensus/src/client/stake_v1.rs
  73. 0 165
      src/contract/consensus/src/client/unstake_request_v1.rs
  74. 0 111
      src/contract/consensus/src/client/unstake_v1.rs
  75. 0 264
      src/contract/consensus/src/entrypoint.rs
  76. 0 164
      src/contract/consensus/src/entrypoint/genesis_stake_v1.rs
  77. 0 249
      src/contract/consensus/src/entrypoint/proposal_v1.rs
  78. 0 202
      src/contract/consensus/src/entrypoint/stake_v1.rs
  79. 0 193
      src/contract/consensus/src/entrypoint/unstake_request_v1.rs
  80. 0 173
      src/contract/consensus/src/entrypoint/unstake_v1.rs
  81. 0 49
      src/contract/consensus/src/error.rs
  82. 0 61
      src/contract/consensus/src/lib.rs
  83. 0 138
      src/contract/consensus/src/model.rs
  84. 0 146
      src/contract/consensus/tests/genesis_stake_unstake.rs
  85. 0 226
      src/contract/consensus/tests/stake_unstake.rs
  86. 1 66
      src/contract/money/src/client/mod.rs
  87. 0 225
      src/contract/money/src/client/stake_v1.rs
  88. 0 199
      src/contract/money/src/client/unstake_v1.rs
  89. 1 29
      src/contract/money/src/entrypoint.rs
  90. 0 183
      src/contract/money/src/entrypoint/stake_v1.rs
  91. 0 199
      src/contract/money/src/entrypoint/unstake_v1.rs
  92. 14 46
      src/contract/money/src/error.rs
  93. 2 32
      src/contract/money/src/lib.rs
  94. 0 113
      src/contract/money/src/model.rs
  95. 0 1
      src/contract/test-harness/Cargo.toml
  96. 0 119
      src/contract/test-harness/src/consensus_genesis_stake.rs
  97. 0 179
      src/contract/test-harness/src/consensus_proposal.rs
  98. 0 195
      src/contract/test-harness/src/consensus_stake.rs
  99. 0 181
      src/contract/test-harness/src/consensus_unstake.rs
  100. 0 182
      src/contract/test-harness/src/consensus_unstake_request.rs

+ 1 - 25
Cargo.lock

@@ -1931,7 +1931,6 @@ dependencies = [
  "darkfi",
  "darkfi",
  "darkfi-sdk",
  "darkfi-sdk",
  "darkfi-serial",
  "darkfi-serial",
- "darkfi_consensus_contract",
  "darkfi_dao_contract",
  "darkfi_dao_contract",
  "darkfi_deployooor_contract",
  "darkfi_deployooor_contract",
  "darkfi_money_contract",
  "darkfi_money_contract",
@@ -2032,28 +2031,6 @@ dependencies = [
  "url",
  "url",
 ]
 ]
 
 
-[[package]]
-name = "darkfi_consensus_contract"
-version = "0.4.1"
-dependencies = [
- "blake3 1.5.0",
- "bs58",
- "chacha20poly1305",
- "darkfi",
- "darkfi-contract-test-harness",
- "darkfi-sdk",
- "darkfi-serial",
- "darkfi_money_contract",
- "getrandom 0.2.12",
- "halo2_proofs",
- "log",
- "rand 0.8.5",
- "simplelog",
- "sled",
- "smol",
- "thiserror",
-]
-
 [[package]]
 [[package]]
 name = "darkfi_dao_contract"
 name = "darkfi_dao_contract"
 version = "0.4.1"
 version = "0.4.1"
@@ -2114,7 +2091,7 @@ dependencies = [
 ]
 ]
 
 
 [[package]]
 [[package]]
-name = "darkfid2"
+name = "darkfid"
 version = "0.4.1"
 version = "0.4.1"
 dependencies = [
 dependencies = [
  "async-trait",
  "async-trait",
@@ -2124,7 +2101,6 @@ dependencies = [
  "darkfi-contract-test-harness",
  "darkfi-contract-test-harness",
  "darkfi-sdk",
  "darkfi-sdk",
  "darkfi-serial",
  "darkfi-serial",
- "darkfi_consensus_contract",
  "darkfi_money_contract",
  "darkfi_money_contract",
  "easy-parallel",
  "easy-parallel",
  "log",
  "log",

+ 1 - 3
Cargo.toml

@@ -20,8 +20,7 @@ doctest = false
 [workspace]
 [workspace]
 members = [
 members = [
     "bin/zkas",
     "bin/zkas",
-    #"bin/darkfid",
-    "bin/darkfid2",
+    "bin/darkfid",
     "bin/darkfi-mmproxy",
     "bin/darkfi-mmproxy",
     "bin/drk",
     "bin/drk",
     #"bin/faucetd",
     #"bin/faucetd",
@@ -46,7 +45,6 @@ members = [
     "src/contract/test-harness",
     "src/contract/test-harness",
     "src/contract/money",
     "src/contract/money",
     "src/contract/dao",
     "src/contract/dao",
-    "src/contract/consensus",
     "src/contract/deployooor",
     "src/contract/deployooor",
 
 
     "example/dchat/dchatd",
     "example/dchat/dchatd",

+ 3 - 5
Makefile

@@ -18,7 +18,7 @@ PROOFS_BIN = $(PROOFS_SRC:=.bin)
 # List of all binaries built
 # List of all binaries built
 BINS = \
 BINS = \
 	zkas \
 	zkas \
-	darkfid2 \
+	darkfid \
 	darkfi-mmproxy \
 	darkfi-mmproxy \
 	darkirc \
 	darkirc \
 	genev \
 	genev \
@@ -42,11 +42,10 @@ $(PROOFS_BIN): zkas $(PROOFS_SRC)
 
 
 contracts: zkas
 contracts: zkas
 	$(MAKE) -C src/contract/money
 	$(MAKE) -C src/contract/money
-	$(MAKE) -C src/contract/consensus
 	$(MAKE) -C src/contract/dao
 	$(MAKE) -C src/contract/dao
 	$(MAKE) -C src/contract/deployooor
 	$(MAKE) -C src/contract/deployooor
 
 
-darkfid2: contracts
+darkfid: contracts
 	$(MAKE) -C bin/$@ \
 	$(MAKE) -C bin/$@ \
 		PREFIX="$(PREFIX)" \
 		PREFIX="$(PREFIX)" \
 		CARGO="$(CARGO)" \
 		CARGO="$(CARGO)" \
@@ -147,11 +146,10 @@ coverage: contracts $(PROOFS_BIN)
 
 
 clean:
 clean:
 	$(MAKE) -C src/contract/money clean
 	$(MAKE) -C src/contract/money clean
-	$(MAKE) -C src/contract/consensus clean
 	$(MAKE) -C src/contract/dao clean
 	$(MAKE) -C src/contract/dao clean
 	$(MAKE) -C src/contract/deployooor clean
 	$(MAKE) -C src/contract/deployooor clean
 	$(MAKE) -C bin/zkas clean
 	$(MAKE) -C bin/zkas clean
-	$(MAKE) -C bin/darkfid2 clean
+	$(MAKE) -C bin/darkfid clean
 	$(MAKE) -C bin/darkfi-mmproxy clean
 	$(MAKE) -C bin/darkfi-mmproxy clean
 	$(MAKE) -C bin/darkirc clean
 	$(MAKE) -C bin/darkirc clean
 	$(MAKE) -C bin/genev/genev-cli clean
 	$(MAKE) -C bin/genev/genev-cli clean

+ 14 - 4
bin/darkfid/Cargo.toml

@@ -9,14 +9,24 @@ license = "AGPL-3.0-only"
 edition = "2021"
 edition = "2021"
 
 
 [dependencies]
 [dependencies]
-async-trait = "0.1.77"
+# Darkfi
+darkfi = {path = "../../", features = ["async-daemonize", "bs58"]}
+darkfi_money_contract = {path = "../../src/contract/money"}
+darkfi-contract-test-harness = {path = "../../src/contract/test-harness"}
+darkfi-sdk = {path = "../../src/sdk"}
+darkfi-serial = {path = "../../src/serial"}
+
+# Misc
 blake3 = "1.5.0"
 blake3 = "1.5.0"
 bs58 = "0.5.0"
 bs58 = "0.5.0"
-darkfi = {path = "../../", features = ["async-daemonize", "validator"]}
-darkfi-sdk = {path = "../../src/sdk", features = ["async"]}
-darkfi-serial = {path = "../../src/serial"}
 log = "0.4.20"
 log = "0.4.20"
+num-bigint = "0.4.4"
+rand = "0.8.5"
 sled = "0.34.7"
 sled = "0.34.7"
+toml = "0.8.8"
+
+# JSON-RPC
+async-trait = "0.1.77"
 tinyjson = "2.5.1"
 tinyjson = "2.5.1"
 url = "2.5.0"
 url = "2.5.0"
 
 

+ 16 - 8
bin/darkfid/Makefile

@@ -6,29 +6,37 @@ PREFIX = $(HOME)/.cargo
 # Cargo binary
 # Cargo binary
 CARGO = cargo +nightly
 CARGO = cargo +nightly
 
 
+# Compile target
+RUST_TARGET = $(shell rustc -Vv | grep '^host: ' | cut -d' ' -f2)
+# Uncomment when doing musl static builds
+#RUSTFLAGS = -C target-feature=+crt-static -C link-self-contained=yes
+
 SRC = \
 SRC = \
 	Cargo.toml \
 	Cargo.toml \
 	../../Cargo.toml \
 	../../Cargo.toml \
-	$(shell find src -type f) \
-	$(shell find ../../src -type f) \
+	$(shell find src -type f -name '*.rs') \
+	$(shell find ../../src -type f -name '*.rs') \
+	$(shell find ../../src/contract -type f -name '*.wasm')
 
 
-BIN = ../../darkfid
+BIN = $(shell grep '^name = ' Cargo.toml | cut -d' ' -f3 | tr -d '"')
 
 
 all: $(BIN)
 all: $(BIN)
 
 
 $(BIN): $(SRC)
 $(BIN): $(SRC)
-	$(CARGO) build $(TARGET_PRFX)$(RUST_TARGET) --release --package darkfid
-	cp -f ../../target/$(RUST_TARGET)/release/darkfid $@
+	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) build --target=$(RUST_TARGET) --release --package $@
+	cp -f ../../target/$(RUST_TARGET)/release/$@ $@
+	cp -f ../../target/$(RUST_TARGET)/release/$@ ../../$@
 
 
 clean:
 clean:
-	rm -f $(BIN)
+	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clean --target=$(RUST_TARGET) --release --package $(BIN)
+	rm -f $(BIN) ../../$(BIN)
 
 
 install: all
 install: all
 	mkdir -p $(DESTDIR)$(PREFIX)/bin
 	mkdir -p $(DESTDIR)$(PREFIX)/bin
 	cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
 	cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
-	chmod 755 $(DESTDIR)$(PREFIX)/bin/darkfid
+	chmod 755 $(DESTDIR)$(PREFIX)/bin/$(BIN)
 
 
 uninstall:
 uninstall:
-	rm -f $(DESTDIR)$(PREFIX)/bin/darkfid
+	rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN)
 
 
 .PHONY: all clean install uninstall
 .PHONY: all clean install uninstall

+ 437 - 47
bin/darkfid/darkfid_config.toml

@@ -6,80 +6,470 @@
 ## The default values are left commented. They can be overridden either by
 ## The default values are left commented. They can be overridden either by
 ## uncommenting, or by using the command-line.
 ## uncommenting, or by using the command-line.
 
 
-# Chain to use (testnet, mainnet)
-chain = "testnet"
+# JSON-RPC listen URL
+rpc_listen = "tcp://127.0.0.1:8340"
+
+# Blockchain network to use
+network = "testnet"
+
+# Localnet blockchain network configuration
+[network_config."localnet"]
+# Path to the blockchain database directory
+database = "~/.local/darkfi/darkfid_blockchain_localnet"
+
+# Finalization threshold, denominated by number of blocks
+threshold = 3
+
+# minerd JSON-RPC endpoint
+minerd_endpoint = "tcp://127.0.0.1:28467"
+
+# PoW block production target, in seconds
+pow_target = 10
+
+# Optional fixed PoW difficulty, used for testing
+pow_fixed_difficulty = 1
+
+# Epoch duration, denominated by number of blocks/slots
+epoch_length = 10
+
+# PoS slot duration, in seconds
+slot_time = 10
+
+# Whitelisted faucet addresses
+faucet_pub = []
+
+# Participate in the consensus protocol
+consensus = true
+
+# Wallet address to receive consensus rewards.
+# This is a dummy one so the miner can start,
+# replace with your own one.
+recipient = "5ZHfYpt4mpJcwBNxfEyxLzeFJUEeoePs5NQ5jVEgHrMf"
+
+# Skip syncing process and start node right away
+skip_sync = true
+
+# Enable PoS testing mode for local testing
+pos_testing_mode = true
+
+## Localnet sync P2P network settings
+[network_config."localnet".sync_net]
+# P2P accept addresses the instance listens on for inbound connections
+inbound = ["tcp+tls://0.0.0.0:8242"]
+
+# P2P external addresses the instance advertises so other peers can
+# reach us and connect to us, as long as inbound addrs are configured.
+#external_addrs = []
+
+# Peer nodes to manually connect to
+#peers = []
+
+# Seed nodes to connect to for peer discovery and/or adversising our
+# own external addresses
+#seeds = []
+
+# Whitelisted network transports for outbound connections
+#allowed_transports = ["tcp+tls"]
+
+# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
+#transport_mixing = true
+
+# Outbound connection slots number, this many connections will be
+# attempted. (This does not include manual connections)
+#outbound_connections = 8
+
+# Inbound connections slots number, this many active inbound connections
+# will be allowed. (This does not include manual or outbound connections)
+#inbound_connections = 0
+
+# Manual connections retry limit, 0 for forever looping
+#manual_attempt_limit = 0
+
+# Outbound connection timeout (in seconds)
+#outbound_connect_timeout = 10
+
+# Exchange versions (handshake) timeout (in seconds)
+#channel_handshake_timeout = 4
+
+# Ping-pong exchange execution interval (in seconds)
+#channel_heartbeat_interval = 10
 
 
-# Path to the wallet database
-wallet_path = "~/.config/darkfi/darkfid_wallet_testnet.db"
+# Allow localnet hosts
+localnet = true
 
 
-# Password for the wallet database
-#wallet_pass = "changeme"
+# Delete a peer from hosts if they've been quarantined N times
+#hosts_quarantine_limit = 50
 
 
+# Cooling off time for peer discovery when unsuccessful
+#outbound_peer_discovery_cooloff_time = 30
+
+# Time between peer discovery attempts
+#outbound_peer_discovery_attempt_time = 5
+
+## Localnet consensus P2P network settings
+[network_config."localnet".consensus_net]
+# P2P accept addresses the instance listens on for inbound connections
+#inbound = ["tcp+tls://0.0.0.0:8241"]
+
+# P2P external addresses the instance advertises so other peers can
+# reach us and connect to us, as long as inbound addrs are configured.
+#external_addrs = []
+
+# Peer nodes to manually connect to
+#peers = []
+
+# Seed nodes to connect to for peer discovery and/or adversising our
+# own external addresses
+#seeds = []
+
+# Whitelisted network transports for outbound connections
+#allowed_transports = ["tcp+tls"]
+
+# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
+#transport_mixing = true
+
+# Outbound connection slots number, this many connections will be
+# attempted. (This does not include manual connections)
+#outbound_connections = 8
+
+# Manual connections retry limit, 0 for forever looping
+#manual_attempt_limit = 0
+
+# Outbound connection timeout (in seconds)
+#outbound_connect_timeout = 10
+
+# Exchange versions (handshake) timeout (in seconds)
+#channel_handshake_timeout = 4
+
+# Ping-pong exchange execution interval (in seconds)
+#channel_heartbeat_interval = 10
+
+# Allow localnet hosts
+localnet = true
+
+# Delete a peer from hosts if they've been quarantined N times
+#hosts_quarantine_limit = 50
+
+# Cooling off time for peer discovery when unsuccessful
+#outbound_peer_discovery_cooloff_time = 30
+
+# Time between peer discovery attempts
+#outbound_peer_discovery_attempt_time = 5
+
+# Testnet blockchain network configuration
+[network_config."testnet"]
 # Path to the blockchain database directory
 # Path to the blockchain database directory
-database = "~/.config/darkfi/darkfid_blockchain_testnet"
+database = "~/.local/darkfi/darkfid_blockchain_testnet"
 
 
-# JSON-RPC listen URL
-rpc_listen = "tcp://127.0.0.1:8340"
+# Finalization threshold, denominated by number of blocks
+threshold = 6
+
+# minerd JSON-RPC endpoint
+minerd_endpoint = "tcp://127.0.0.1:28467"
+
+# PoW block production target, in seconds
+pow_target = 90
+
+# Epoch duration, denominated by number of blocks/slots
+epoch_length = 10
+
+# PoS slot duration, in seconds
+slot_time = 90
+
+# Whitelisted faucet addresses
+faucet_pub = ["3ce5xa3PjuQGFtTaF7AvMJp7fGxqeGRJx7zj3LCwNCkP"]
 
 
 # Participate in the consensus protocol
 # Participate in the consensus protocol
 consensus = false
 consensus = false
 
 
-# Enable single-node mode for local testing
-single_node = false
+# Wallet address to receive consensus rewards
+#recipient = "YOUR_WALLET_ADDRESS_HERE"
 
 
-# P2P accept addresses for the consensus protocol
-#consensus_p2p_accept = ["tls://127.0.0.1:8341"]
+# Skip syncing process and start node right away
+skip_sync = false
 
 
-# P2P external addresses for the consensus protocol
-#consensus_p2p_external = ["tls://127.0.0.1:8341"]
+# Enable PoS testing mode for local testing
+pos_testing_mode = false
 
 
-# Connection slots for the consensus protocol
-#consensus_slots = 8
+## Testnet sync P2P network settings
+[network_config."testnet".sync_net]
+# P2P accept addresses the instance listens on for inbound connections
+# You can also use an IPv6 address
+inbound = ["tcp+tls://0.0.0.0:8342"]
+# IPv6 version:
+#inbound = ["tcp+tls://[::]:8342"]
+# Combined:
+#inbound = ["tcp+tls://0.0.0.0:8342", "tcp+tls://[::]:8342"]
 
 
-# Seed nodes to connect to for the consensus protocol
-#consensus_p2p_seed = []
+# P2P external addresses the instance advertises so other peers can
+# reach us and connect to us, as long as inbound addrs are configured.
+# You can also use an IPv6 address
+#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8342"]
+# IPv6 version:
+#external_addrs = ["tcp+tls://[ipv6 address here]:8342"]
+# Combined:
+#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8342", "tcp+tls://[ipv6 address here]:8342"]
 
 
-# Seed nodes JSON-RPC listen URL for clock synchronization
-#consensus_seed_rpc = []
+# Peer nodes to manually connect to
+#peers = []
 
 
-# Peers to connect to for the consensus protocol
-#consensus_p2p_peer = []
+# Seed nodes to connect to for peer discovery and/or adversising our
+# own external addresses
+seeds = ["tcp+tls://lilith0.dark.fi:8342", "tcp+tls://lilith1.dark.fi:8342"]
 
 
-# Peers JSON-RPC listen URL for clock synchronization
-#consensus_peer_rpc = []
+# Whitelisted network transports for outbound connections
+allowed_transports = ["tcp+tls"]
 
 
-# Prefered transports of outbound connections for the consensus protocol
-#consensus_p2p_transports = ["tls", "tcp"]
+# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
+#transport_mixing = true
 
 
-# P2P accept addresses for the syncing protocol
-sync_p2p_accept = ["tls://0.0.0.0:8342"]
+# Outbound connection slots number, this many connections will be
+# attempted. (This does not include manual connections)
+outbound_connections = 8
 
 
-# P2P external addresses for the syncing protocol
-#sync_p2p_external = ["tls://127.0.0.1:8342"]
+# Inbound connections slots number, this many active inbound connections
+# will be allowed. (This does not include manual or outbound connections)
+#inbound_connections = 0
 
 
-# Connection slots for the syncing protocol
-sync_slots = 8
+# Manual connections retry limit, 0 for forever looping
+#manual_attempt_limit = 0
 
 
-# Seed nodes to connect to for the syncing protocol
-sync_p2p_seed = ["tls://lilith0.dark.fi:8342", "tls://lilith1.dark.fi:8342"]
+# Outbound connection timeout (in seconds)
+#outbound_connect_timeout = 10
 
 
-# Peers to connect to for the syncing protocol
-#sync_p2p_peer = []
+# Exchange versions (handshake) timeout (in seconds)
+#channel_handshake_timeout = 4
 
 
-# Prefered transports of outbound connections for the syncing protocol
-sync_p2p_transports = ["tls"]
+# Ping-pong exchange execution interval (in seconds)
+#channel_heartbeat_interval = 10
 
 
-# Enable localnet hosts
+# Allow localnet hosts
 localnet = false
 localnet = false
 
 
-# Enable channel log
-#channel_log = false
+# Delete a peer from hosts if they've been quarantined N times
+#hosts_quarantine_limit = 50
+
+# Cooling off time for peer discovery when unsuccessful
+#outbound_peer_discovery_cooloff_time = 30
+
+# Time between peer discovery attempts
+#outbound_peer_discovery_attempt_time = 5
+
+## Testnet consensus P2P network settings
+[network_config."testnet".consensus_net]
+# P2P accept addresses the instance listens on for inbound connections
+# You can also use an IPv6 address
+inbound = ["tcp+tls://0.0.0.0:8341"]
+# IPv6 version:
+#inbound = ["tcp+tls://[::]:8341"]
+# Combined:
+#inbound = ["tcp+tls://0.0.0.0:8341", "tcp+tls://[::]:8341"]
+
+# P2P external addresses the instance advertises so other peers can
+# reach us and connect to us, as long as inbound addrs are configured.
+# You can also use an IPv6 address
+#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8341"]
+# IPv6 version:
+#external_addrs = ["tcp+tls://[ipv6 address here]:8341"]
+# Combined:
+#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8341", "tcp+tls://[ipv6 address here]:8341"]
 
 
-# Whitelisted cashier addresses
-#cashier_pub = []
+# Peer nodes to manually connect to
+#peers = []
+
+# Seed nodes to connect to for peer discovery and/or adversising our
+# own external addresses
+seeds = ["tcp+tls://lilith0.dark.fi:8341", "tcp+tls://lilith1.dark.fi:8341"]
+
+# Whitelisted network transports for outbound connections
+allowed_transports = ["tcp+tls"]
+
+# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
+#transport_mixing = true
+
+# Outbound connection slots number, this many connections will be
+# attempted. (This does not include manual connections)
+#outbound_connections = 8
+
+# Manual connections retry limit, 0 for forever looping
+#manual_attempt_limit = 0
+
+# Outbound connection timeout (in seconds)
+#outbound_connect_timeout = 10
+
+# Exchange versions (handshake) timeout (in seconds)
+#channel_handshake_timeout = 4
+
+# Ping-pong exchange execution interval (in seconds)
+#channel_heartbeat_interval = 10
+
+# Allow localnet hosts
+localnet = false
+
+# Delete a peer from hosts if they've been quarantined N times
+#hosts_quarantine_limit = 50
+
+# Cooling off time for peer discovery when unsuccessful
+#outbound_peer_discovery_cooloff_time = 30
+
+# Time between peer discovery attempts
+#outbound_peer_discovery_attempt_time = 5
+
+# Mainnet blockchain network configuration
+[network_config."mainnet"]
+# Path to the blockchain database directory
+database = "~/.local/darkfi/darkfid_blockchain_mainnet"
+
+# Finalization threshold, denominated by number of blocks
+threshold = 11
+
+# minerd JSON-RPC endpoint
+minerd_endpoint = "tcp://127.0.0.1:28467"
+
+# PoW block production target, in seconds
+pow_target = 90
+
+# Epoch duration, denominated by number of blocks/slots
+epoch_length = 10
+
+# PoS slot duration, in seconds
+slot_time = 90
 
 
 # Whitelisted faucet addresses
 # Whitelisted faucet addresses
-faucet_pub = ["3ce5xa3PjuQGFtTaF7AvMJp7fGxqeGRJx7zj3LCwNCkP"]
+faucet_pub = []
+
+# Participate in the consensus protocol
+consensus = false
+
+# Wallet address to receive consensus rewards
+#recipient = "YOUR_WALLET_ADDRESS_HERE"
+
+# Skip syncing process and start node right away
+skip_sync = false
+
+# Enable PoS testing mode for local testing
+pos_testing_mode = false
+
+## Mainnet sync P2P network settings
+[network_config."mainnet".sync_net]
+# P2P accept addresses the instance listens on for inbound connections
+# You can also use an IPv6 address
+inbound = ["tcp+tls://0.0.0.0:8442"]
+# IPv6 version:
+#inbound = ["tcp+tls://[::]:8442"]
+# Combined:
+#inbound = ["tcp+tls://0.0.0.0:8442", "tcp+tls://[::]:8442"]
+
+# P2P external addresses the instance advertises so other peers can
+# reach us and connect to us, as long as inbound addrs are configured.
+# You can also use an IPv6 address
+#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8442"]
+# IPv6 version:
+#external_addrs = ["tcp+tls://[ipv6 address here]:8442"]
+# Combined:
+#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8442", "tcp+tls://[ipv6 address here]:8442"]
+
+# Peer nodes to manually connect to
+#peers = []
+
+# Seed nodes to connect to for peer discovery and/or adversising our
+# own external addresses
+seeds = ["tcp+tls://lilith0.dark.fi:8442", "tcp+tls://lilith1.dark.fi:8442"]
+
+# Whitelisted network transports for outbound connections
+allowed_transports = ["tcp+tls"]
+
+# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
+#transport_mixing = true
+
+# Outbound connection slots number, this many connections will be
+# attempted. (This does not include manual connections)
+outbound_connections = 8
+
+# Inbound connections slots number, this many active inbound connections
+# will be allowed. (This does not include manual or outbound connections)
+#inbound_connections = 0
+
+# Manual connections retry limit, 0 for forever looping
+#manual_attempt_limit = 0
+
+# Outbound connection timeout (in seconds)
+#outbound_connect_timeout = 10
+
+# Exchange versions (handshake) timeout (in seconds)
+#channel_handshake_timeout = 4
+
+# Ping-pong exchange execution interval (in seconds)
+#channel_heartbeat_interval = 10
+
+# Allow localnet hosts
+localnet = false
+
+# Delete a peer from hosts if they've been quarantined N times
+#hosts_quarantine_limit = 50
+
+# Cooling off time for peer discovery when unsuccessful
+#outbound_peer_discovery_cooloff_time = 30
+
+# Time between peer discovery attempts
+#outbound_peer_discovery_attempt_time = 5
+
+## Mainnet consensus P2P network settings
+[network_config."mainnet".consensus_net]
+# P2P accept addresses the instance listens on for inbound connections
+# You can also use an IPv6 address
+inbound = ["tcp+tls://0.0.0.0:8441"]
+# IPv6 version:
+#inbound = ["tcp+tls://[::]:8441"]
+# Combined:
+#inbound = ["tcp+tls://0.0.0.0:8441", "tcp+tls://[::]:8441"]
+
+# P2P external addresses the instance advertises so other peers can
+# reach us and connect to us, as long as inbound addrs are configured.
+# You can also use an IPv6 address
+#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8441"]
+# IPv6 version:
+#external_addrs = ["tcp+tls://[ipv6 address here]:8441"]
+# Combined:
+#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8441", "tcp+tls://[ipv6 address here]:8441"]
+
+# Peer nodes to manually connect to
+#peers = []
+
+# Seed nodes to connect to for peer discovery and/or adversising our
+# own external addresses
+seeds = ["tcp+tls://lilith0.dark.fi:8441", "tcp+tls://lilith1.dark.fi:8441"]
+
+# Whitelisted network transports for outbound connections
+allowed_transports = ["tcp+tls"]
+
+# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
+#transport_mixing = true
+
+# Outbound connection slots number, this many connections will be
+# attempted. (This does not include manual connections)
+#outbound_connections = 8
+
+# Manual connections retry limit, 0 for forever looping
+#manual_attempt_limit = 0
+
+# Outbound connection timeout (in seconds)
+#outbound_connect_timeout = 10
+
+# Exchange versions (handshake) timeout (in seconds)
+#channel_handshake_timeout = 4
+
+# Ping-pong exchange execution interval (in seconds)
+#channel_heartbeat_interval = 10
+
+# Allow localnet hosts
+localnet = false
+
+# Delete a peer from hosts if they've been quarantined N times
+#hosts_quarantine_limit = 50
+
+# Cooling off time for peer discovery when unsuccessful
+#outbound_peer_discovery_cooloff_time = 30
 
 
-# Verify system clock is correct
-#clock_sync = true
+# Time between peer discovery attempts
+#outbound_peer_discovery_attempt_time = 5

+ 0 - 0
bin/darkfid2/genesis_block_localnet → bin/darkfid/genesis_block_localnet


+ 0 - 0
bin/darkfid2/genesis_block_mainnet → bin/darkfid/genesis_block_mainnet


+ 0 - 0
bin/darkfid2/genesis_block_testnet → bin/darkfid/genesis_block_testnet


+ 5 - 20
bin/darkfid/src/error.rs

@@ -21,16 +21,6 @@ use darkfi::rpc::jsonrpc::{ErrorCode::ServerError, JsonError, JsonResult};
 /// Custom RPC errors available for darkfid.
 /// Custom RPC errors available for darkfid.
 /// Please sort them sensefully.
 /// Please sort them sensefully.
 pub enum RpcError {
 pub enum RpcError {
-    /*
-    // Wallet/Key-related errors
-    NoRowsFoundInWallet = -32101,
-    Keygen = -32101,
-    KeypairFetch = -32102,
-    KeypairNotFound = -32103,
-    InvalidKeypair = -32104,
-    InvalidAddressParam = -32105,
-    DecryptionFailed = -32106,
-    */
     // Transaction-related errors
     // Transaction-related errors
     TxSimulationFail = -32110,
     TxSimulationFail = -32110,
     TxBroadcastFail = -32111,
     TxBroadcastFail = -32111,
@@ -44,20 +34,13 @@ pub enum RpcError {
 
 
     // Contract-related errors
     // Contract-related errors
     ContractZkasDbNotFound = -32200,
     ContractZkasDbNotFound = -32200,
+
+    // Misc errors
+    PingFailed = -32300,
 }
 }
 
 
 fn to_tuple(e: RpcError) -> (i32, String) {
 fn to_tuple(e: RpcError) -> (i32, String) {
     let msg = match e {
     let msg = match e {
-        /*
-        // Wallet/Key-related errors
-        RpcError::NoRowsFoundInWallet => "No queried rows found in wallet",
-        RpcError::Keygen => "Failed generating keypair",
-        RpcError::KeypairFetch => "Failed fetching keypairs from wallet",
-        RpcError::KeypairNotFound => "Keypair not found",
-        RpcError::InvalidKeypair => "Invalid keypair",
-        RpcError::InvalidAddressParam => "Invalid address parameter",
-        RpcError::DecryptionFailed => "Decryption failed",
-        */
         // Transaction-related errors
         // Transaction-related errors
         RpcError::TxSimulationFail => "Failed simulating transaction state change",
         RpcError::TxSimulationFail => "Failed simulating transaction state change",
         RpcError::TxBroadcastFail => "Failed broadcasting transaction",
         RpcError::TxBroadcastFail => "Failed broadcasting transaction",
@@ -68,6 +51,8 @@ fn to_tuple(e: RpcError) -> (i32, String) {
         RpcError::ParseError => "Parse error",
         RpcError::ParseError => "Parse error",
         // Contract-related errors
         // Contract-related errors
         RpcError::ContractZkasDbNotFound => "zkas database not found for given contract",
         RpcError::ContractZkasDbNotFound => "zkas database not found for given contract",
+        // Misc errors
+        RpcError::PingFailed => "Miner daemon ping error",
     };
     };
 
 
     (e as i32, msg.to_string())
     (e as i32, msg.to_string())

+ 259 - 365
bin/darkfid/src/main.rs

@@ -16,49 +16,65 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
  */
 
 
-use std::{collections::HashSet, path::Path, str::FromStr, sync::Arc};
+use std::{
+    collections::{HashMap, HashSet},
+    str::FromStr,
+    sync::Arc,
+};
 
 
-use async_trait::async_trait;
-use darkfi_sdk::crypto::PublicKey;
 use log::{error, info};
 use log::{error, info};
-use smol::{
-    lock::{Mutex, MutexGuard},
-    stream::StreamExt,
-};
+use smol::{lock::Mutex, stream::StreamExt};
 use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml};
 use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml};
 use url::Url;
 use url::Url;
 
 
 use darkfi::{
 use darkfi::{
-    async_daemonize, cli_desc,
-    consensus::{
-        constants::{
-            MAINNET_BOOTSTRAP_TIMESTAMP, MAINNET_GENESIS_HASH_BYTES, MAINNET_GENESIS_TIMESTAMP,
-            MAINNET_INITIAL_DISTRIBUTION, TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES,
-            TESTNET_GENESIS_TIMESTAMP, TESTNET_INITIAL_DISTRIBUTION,
-        },
-        proto::{ProtocolProposal, ProtocolSync, ProtocolSyncConsensus, ProtocolTx},
-        task::{block_sync_task, proposal_task},
-        validator::ValidatorStatePtr,
-        ValidatorState,
-    },
-    net,
-    net::P2pPtr,
+    async_daemonize,
+    blockchain::BlockInfo,
+    cli_desc,
+    net::{settings::SettingsOpt, P2pPtr},
     rpc::{
     rpc::{
-        clock_sync::check_clock,
-        jsonrpc::{ErrorCode::MethodNotFound, JsonError, JsonRequest, JsonResult},
+        client::RpcClient,
+        jsonrpc::JsonSubscriber,
         server::{listen_and_serve, RequestHandler},
         server::{listen_and_serve, RequestHandler},
     },
     },
     system::{StoppableTask, StoppableTaskPtr},
     system::{StoppableTask, StoppableTaskPtr},
-    util::path::expand_path,
-    wallet::{WalletDb, WalletPtr},
+    util::{path::expand_path, time::TimeKeeper},
+    validator::{utils::genesis_txs_total, Validator, ValidatorConfig, ValidatorPtr},
     Error, Result,
     Error, Result,
 };
 };
+use darkfi_sdk::crypto::PublicKey;
+use darkfi_serial::deserialize_async;
+
+#[cfg(test)]
+mod tests;
 
 
 mod error;
 mod error;
 use error::{server_error, RpcError};
 use error::{server_error, RpcError};
 
 
+/// JSON-RPC requests handler and methods
+mod rpc;
+mod rpc_blockchain;
+mod rpc_tx;
+
+/// Validator async tasks
+mod task;
+use task::{miner_task, sync_task};
+
+/// P2P net protocols
+mod proto;
+
+/// Utility functions
+mod utils;
+use utils::{parse_blockchain_config, spawn_consensus_p2p, spawn_sync_p2p};
+
 const CONFIG_FILE: &str = "darkfid_config.toml";
 const CONFIG_FILE: &str = "darkfid_config.toml";
 const CONFIG_FILE_CONTENTS: &str = include_str!("../darkfid_config.toml");
 const CONFIG_FILE_CONTENTS: &str = include_str!("../darkfid_config.toml");
+/// Note:
+/// If you change these don't forget to remove their corresponding database folder,
+/// since if it already has a genesis block, provided one is ignored.
+const GENESIS_BLOCK_LOCALNET: &str = include_str!("../genesis_block_localnet");
+const GENESIS_BLOCK_TESTNET: &str = include_str!("../genesis_block_testnet");
+const GENESIS_BLOCK_MAINNET: &str = include_str!("../genesis_block_mainnet");
 
 
 #[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
 #[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
 #[serde(default)]
 #[serde(default)]
@@ -68,381 +84,247 @@ struct Args {
     /// Configuration file to use
     /// Configuration file to use
     config: Option<String>,
     config: Option<String>,
 
 
-    #[structopt(long, default_value = "testnet")]
-    /// Chain to use (testnet, mainnet)
-    chain: String,
-
-    #[structopt(long)]
-    /// Participate in consensus
-    consensus: bool,
-
-    #[structopt(long)]
-    /// Enable single-node mode for local testing
-    single_node: bool,
-
-    #[structopt(long, default_value = "~/.config/darkfi/darkfid_wallet.db")]
-    /// Path to wallet database
-    wallet_path: String,
-
-    #[structopt(long, default_value = "changeme")]
-    /// Password for the wallet database
-    wallet_pass: String,
-
-    #[structopt(long, default_value = "~/.config/darkfi/darkfid_blockchain")]
-    /// Path to blockchain database
-    database: String,
-
-    #[structopt(long, default_value = "tcp://127.0.0.1:8340")]
+    #[structopt(short, long, default_value = "tcp://127.0.0.1:8340")]
     /// JSON-RPC listen URL
     /// JSON-RPC listen URL
     rpc_listen: Url,
     rpc_listen: Url,
 
 
-    #[structopt(long)]
-    /// P2P accept addresses for the consensus protocol (repeatable flag)
-    consensus_p2p_accept: Vec<Url>,
-
-    #[structopt(long)]
-    /// P2P external addresses for the consensus protocol (repeatable flag)
-    consensus_p2p_external: Vec<Url>,
-
-    #[structopt(long, default_value = "8")]
-    /// Connection slots for the consensus protocol
-    consensus_slots: usize,
-
-    #[structopt(long)]
-    /// Connect to peer for the consensus protocol (repeatable flag)
-    consensus_p2p_peer: Vec<Url>,
-
-    #[structopt(long)]
-    /// Peers JSON-RPC listen URL for clock synchronization (repeatable flag)
-    consensus_peer_rpc: Vec<Url>,
+    #[structopt(short, long, default_value = "testnet")]
+    /// Blockchain network to use
+    network: String,
 
 
-    #[structopt(long)]
-    /// Connect to seed for the consensus protocol (repeatable flag)
-    consensus_p2p_seed: Vec<Url>,
+    #[structopt(short, long)]
+    /// Set log file to ouput into
+    log: Option<String>,
 
 
-    #[structopt(long)]
-    /// Seed nodes JSON-RPC listen URL for clock synchronization (repeatable flag)
-    consensus_seed_rpc: Vec<Url>,
+    #[structopt(short, parse(from_occurrences))]
+    /// Increase verbosity (-vvv supported)
+    verbose: u8,
+}
 
 
-    #[structopt(long)]
-    /// Prefered transports of outbound connections for the consensus protocol (repeatable flag)
-    consensus_p2p_transports: Vec<String>,
+/// Defines a blockchain network configuration.
+/// Default values correspond to a local network.
+#[derive(Clone, Debug, serde::Deserialize, structopt::StructOpt, structopt_toml::StructOptToml)]
+#[structopt()]
+pub struct BlockchainNetwork {
+    #[structopt(long, default_value = "~/.local/darkfi/darkfid_blockchain_localnet")]
+    /// Path to blockchain database
+    pub database: String,
 
 
-    #[structopt(long)]
-    /// P2P accept addresses for the syncing protocol (repeatable flag)
-    sync_p2p_accept: Vec<Url>,
+    #[structopt(long, default_value = "3")]
+    /// Finalization threshold, denominated by number of blocks
+    pub threshold: usize,
 
 
-    #[structopt(long)]
-    /// P2P external addresses for the syncing protocol (repeatable flag)
-    sync_p2p_external: Vec<Url>,
+    #[structopt(long, default_value = "tcp://127.0.0.1:28467")]
+    /// minerd JSON-RPC endpoint
+    pub minerd_endpoint: Url,
 
 
-    #[structopt(long, default_value = "8")]
-    /// Connection slots for the syncing protocol
-    sync_slots: usize,
+    #[structopt(long, default_value = "10")]
+    /// PoW block production target, in seconds
+    pub pow_target: usize,
 
 
     #[structopt(long)]
     #[structopt(long)]
-    /// Connect to peer for the syncing protocol (repeatable flag)
-    sync_p2p_peer: Vec<Url>,
+    /// Optional fixed PoW difficulty, used for testing
+    pub pow_fixed_difficulty: Option<usize>,
 
 
-    #[structopt(long)]
-    /// Connect to seed for the syncing protocol (repeatable flag)
-    sync_p2p_seed: Vec<Url>,
+    #[structopt(long, default_value = "10")]
+    /// Epoch duration, denominated by number of blocks/slots
+    pub epoch_length: u64,
 
 
-    #[structopt(long)]
-    /// Prefered transports of outbound connections for the syncing protocol (repeatable flag)
-    sync_p2p_transports: Vec<String>,
+    #[structopt(long, default_value = "10")]
+    /// PoS slot duration, in seconds
+    pub slot_time: u64,
 
 
     #[structopt(long)]
     #[structopt(long)]
-    /// Enable localnet hosts
-    localnet: bool,
+    /// Whitelisted faucet public key (repeatable flag)
+    pub faucet_pub: Vec<String>,
 
 
     #[structopt(long)]
     #[structopt(long)]
-    /// Enable channel log
-    channel_log: bool,
+    /// Participate in the consensus protocol
+    pub consensus: bool,
 
 
     #[structopt(long)]
     #[structopt(long)]
-    /// Whitelisted cashier public key (repeatable flag)
-    cashier_pub: Vec<String>,
+    /// Wallet address to receive consensus rewards
+    pub recipient: Option<String>,
 
 
     #[structopt(long)]
     #[structopt(long)]
-    /// Whitelisted faucet public key (repeatable flag)
-    faucet_pub: Vec<String>,
+    /// Skip syncing process and start node right away
+    pub skip_sync: bool,
 
 
     #[structopt(long)]
     #[structopt(long)]
-    /// Verify system clock is correct
-    clock_sync: bool,
+    /// Enable PoS testing mode for local testing
+    pub pos_testing_mode: bool,
 
 
-    #[structopt(short, long)]
-    /// Set log file to ouput into
-    log: Option<String>,
+    /// Syncing network settings
+    #[structopt(flatten)]
+    pub sync_net: SettingsOpt,
 
 
-    #[structopt(short, parse(from_occurrences))]
-    /// Increase verbosity (-vvv supported)
-    verbose: u8,
+    /// Consensus network settings
+    #[structopt(flatten)]
+    pub consensus_net: SettingsOpt,
 }
 }
 
 
+/// Daemon structure
 pub struct Darkfid {
 pub struct Darkfid {
-    synced: Mutex<bool>, // AtomicBool is weird in Arc
+    /// Syncing P2P network pointer
+    sync_p2p: P2pPtr,
+    /// Optional consensus P2P network pointer
     consensus_p2p: Option<P2pPtr>,
     consensus_p2p: Option<P2pPtr>,
-    sync_p2p: Option<P2pPtr>,
-    _wallet: WalletPtr,
-    validator_state: ValidatorStatePtr,
+    /// Validator(node) pointer
+    validator: ValidatorPtr,
+    /// A map of various subscribers exporting live info from the blockchain
+    subscribers: HashMap<&'static str, JsonSubscriber>,
+    /// JSON-RPC connection tracker
     rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
     rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
-}
-
-// JSON-RPC methods
-mod rpc_blockchain;
-mod rpc_misc;
-mod rpc_tx;
-mod rpc_wallet;
-
-// Internal methods
-//mod internal;
-
-#[async_trait]
-impl RequestHandler for Darkfid {
-    async fn handle_request(&self, req: JsonRequest) -> JsonResult {
-        match req.method.as_str() {
-            // =====================
-            // Miscellaneous methods
-            // =====================
-            "ping" => return self.pong(req.id, req.params).await,
-            "clock" => return self.misc_clock(req.id, req.params).await,
-            "sync_dnet_switch" => return self.misc_sync_dnet_switch(req.id, req.params).await,
-            "consensus_dnet_switch" => {
-                return self.misc_consensus_dnet_switch(req.id, req.params).await
-            }
-
-            // ==================
-            // Blockchain methods
-            // ==================
-            "blockchain.get_slot" => return self.blockchain_get_slot(req.id, req.params).await,
-            "blockchain.get_tx" => return self.blockchain_get_tx(req.id, req.params).await,
-            "blockchain.last_known_slot" => {
-                return self.blockchain_last_known_slot(req.id, req.params).await
-            }
-            "blockchain.subscribe_blocks" => {
-                return self.blockchain_subscribe_blocks(req.id, req.params).await
-            }
-            "blockchain.subscribe_err_txs" => {
-                return self.blockchain_subscribe_err_txs(req.id, req.params).await
-            }
-            "blockchain.lookup_zkas" => {
-                return self.blockchain_lookup_zkas(req.id, req.params).await
-            }
-
-            // ===================
-            // Transaction methods
-            // ===================
-            "tx.simulate" => return self.tx_simulate(req.id, req.params).await,
-            "tx.broadcast" => return self.tx_broadcast(req.id, req.params).await,
-
-            // ==============
-            // Wallet methods
-            // ==============
-            "wallet.exec_sql" => return self.wallet_exec_sql(req.id, req.params).await,
-            "wallet.query_row_single" => {
-                return self.wallet_query_row_single(req.id, req.params).await
-            }
-            "wallet.query_row_multi" => {
-                return self.wallet_query_row_multi(req.id, req.params).await
-            }
-
-            // ==============
-            // Invalid method
-            // ==============
-            _ => return JsonError::new(MethodNotFound, None, req.id).into(),
-        }
-    }
-
-    async fn connections_mut(&self) -> MutexGuard<'_, HashSet<StoppableTaskPtr>> {
-        self.rpc_connections.lock().await
-    }
+    /// JSON-RPC client to execute requests to the miner daemon
+    rpc_client: Option<RpcClient>,
 }
 }
 
 
 impl Darkfid {
 impl Darkfid {
     pub async fn new(
     pub async fn new(
-        validator_state: ValidatorStatePtr,
+        sync_p2p: P2pPtr,
         consensus_p2p: Option<P2pPtr>,
         consensus_p2p: Option<P2pPtr>,
-        sync_p2p: Option<P2pPtr>,
-        _wallet: WalletPtr,
+        validator: ValidatorPtr,
+        subscribers: HashMap<&'static str, JsonSubscriber>,
+        rpc_client: Option<RpcClient>,
     ) -> Self {
     ) -> Self {
         Self {
         Self {
-            synced: Mutex::new(false),
-            consensus_p2p,
             sync_p2p,
             sync_p2p,
-            _wallet,
-            validator_state,
+            consensus_p2p,
+            validator,
+            subscribers,
             rpc_connections: Mutex::new(HashSet::new()),
             rpc_connections: Mutex::new(HashSet::new()),
+            rpc_client,
         }
         }
     }
     }
 }
 }
 
 
 async_daemonize!(realmain);
 async_daemonize!(realmain);
 async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
 async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
-    if args.consensus && args.clock_sync {
-        // We verify that if peer/seed nodes are configured, their rpc config also exists
-        if ((!args.consensus_p2p_peer.is_empty() && args.consensus_peer_rpc.is_empty()) ||
-            (args.consensus_p2p_peer.is_empty() && !args.consensus_peer_rpc.is_empty())) ||
-            ((!args.consensus_p2p_seed.is_empty() && args.consensus_seed_rpc.is_empty()) ||
-                (args.consensus_p2p_seed.is_empty() && !args.consensus_seed_rpc.is_empty()))
-        {
-            error!(
-                "Consensus peer/seed nodes misconfigured: both p2p and rpc urls must be present"
-            );
-            return Err(Error::ConfigInvalid)
+    info!(target: "darkfid", "Initializing DarkFi node...");
+
+    // Grab blockchain network configuration
+    let (blockchain_config, genesis_block) = match args.network.as_str() {
+        "localnet" => {
+            (parse_blockchain_config(args.config, "localnet").await?, GENESIS_BLOCK_LOCALNET)
         }
         }
-        // We verify that the system clock is valid before initializing
-        let peers = [&args.consensus_peer_rpc[..], &args.consensus_seed_rpc[..]].concat();
-        if (check_clock(&peers).await).is_err() {
-            error!("System clock is invalid, terminating...");
-            return Err(Error::InvalidClock)
-        };
+        "testnet" => {
+            (parse_blockchain_config(args.config, "testnet").await?, GENESIS_BLOCK_TESTNET)
+        }
+        "mainnet" => {
+            (parse_blockchain_config(args.config, "mainnet").await?, GENESIS_BLOCK_MAINNET)
+        }
+        _ => {
+            error!("Unsupported chain `{}`", args.network);
+            return Err(Error::UnsupportedChain)
+        }
+    };
+
+    if blockchain_config.pos_testing_mode {
+        info!(target: "darkfid", "Node is configured to run in PoS testing mode!");
     }
     }
 
 
-    // Initialize or load wallet
-    let wallet = WalletDb::new(Some(expand_path(&args.wallet_path)?), Some(&args.wallet_pass))?;
+    // Parse the genesis block
+    let bytes = bs58::decode(&genesis_block.trim()).into_vec()?;
+    let genesis_block: BlockInfo = deserialize_async(&bytes).await?;
 
 
     // Initialize or open sled database
     // Initialize or open sled database
-    let db_path =
-        Path::new(expand_path(&args.database)?.to_str().unwrap()).join(args.chain.clone());
+    let db_path = expand_path(&blockchain_config.database)?;
     let sled_db = sled::open(&db_path)?;
     let sled_db = sled::open(&db_path)?;
 
 
-    // Initialize validator state
-    let (bootstrap_ts, genesis_ts, genesis_data, initial_distribution) = match args.chain.as_str() {
-        "mainnet" => (
-            *MAINNET_BOOTSTRAP_TIMESTAMP,
-            *MAINNET_GENESIS_TIMESTAMP,
-            *MAINNET_GENESIS_HASH_BYTES,
-            *MAINNET_INITIAL_DISTRIBUTION,
-        ),
-        "testnet" => (
-            *TESTNET_BOOTSTRAP_TIMESTAMP,
-            *TESTNET_GENESIS_TIMESTAMP,
-            *TESTNET_GENESIS_HASH_BYTES,
-            *TESTNET_INITIAL_DISTRIBUTION,
-        ),
-        x => {
-            error!("Unsupported chain `{}`", x);
-            return Err(Error::UnsupportedChain)
-        }
-    };
-    // Parse faucet addresses
-    let mut faucet_pubkeys = vec![];
+    // Initialize validator configuration
+    let genesis_txs_total = genesis_txs_total(&genesis_block.txs).await?;
 
 
-    for i in args.cashier_pub {
-        let pk = PublicKey::from_str(&i)?;
-        faucet_pubkeys.push(pk);
-    }
+    let time_keeper = TimeKeeper::new(
+        genesis_block.header.timestamp,
+        blockchain_config.epoch_length,
+        blockchain_config.slot_time,
+        0,
+    );
 
 
-    for i in args.faucet_pub {
-        let pk = PublicKey::from_str(&i)?;
-        faucet_pubkeys.push(pk);
-    }
+    let pow_fixed_difficulty = if let Some(diff) = blockchain_config.pow_fixed_difficulty {
+        info!(target: "darkfid", "Node is configured to run with fixed PoW difficulty: {}", diff);
+        Some(diff.into())
+    } else {
+        None
+    };
 
 
-    if args.single_node {
-        info!("Node is configured to run in single-node mode!");
-    }
+    let config = ValidatorConfig::new(
+        time_keeper,
+        blockchain_config.threshold,
+        blockchain_config.pow_target,
+        pow_fixed_difficulty,
+        genesis_block,
+        genesis_txs_total,
+        vec![],
+        blockchain_config.pos_testing_mode,
+        false, // TODO: Make configurable
+    );
 
 
-    // Initialize validator state
-    let state = ValidatorState::new(
-        &sled_db,
-        bootstrap_ts,
-        genesis_ts,
-        genesis_data,
-        initial_distribution,
-        wallet.clone(),
-        faucet_pubkeys,
-        args.consensus,
-        args.single_node,
-    )
-    .await?;
-
-    let sync_p2p = {
-        info!("Registering block sync P2P protocols...");
-        let sync_network_settings = net::Settings {
-            inbound_addrs: args.sync_p2p_accept,
-            outbound_connections: args.sync_slots,
-            external_addrs: args.sync_p2p_external,
-            peers: args.sync_p2p_peer.clone(),
-            seeds: args.sync_p2p_seed.clone(),
-            allowed_transports: args.sync_p2p_transports,
-            localnet: args.localnet,
-            ..Default::default()
-        };
+    // Initialize validator
+    let validator = Validator::new(&sled_db, config).await?;
 
 
-        let p2p = net::P2p::new(sync_network_settings, ex.clone()).await;
-        let registry = p2p.protocol_registry();
-
-        let _state = state.clone();
-        registry
-            .register(net::SESSION_ALL, move |channel, p2p| {
-                let state = _state.clone();
-                async move {
-                    ProtocolSync::init(channel, state, p2p, args.consensus)
-                        .await
-                        .unwrap()
-                }
-            })
-            .await;
+    // Here we initialize various subscribers that can export live blockchain/consensus data.
+    let mut subscribers = HashMap::new();
+    subscribers.insert("blocks", JsonSubscriber::new("blockchain.subscribe_blocks"));
+    subscribers.insert("txs", JsonSubscriber::new("blockchain.subscribe_txs"));
+    if blockchain_config.consensus {
+        subscribers.insert("proposals", JsonSubscriber::new("blockchain.subscribe_proposals"));
+    }
 
 
-        let _state = state.clone();
-        registry
-            .register(net::SESSION_ALL, move |channel, p2p| {
-                let state = _state.clone();
-                async move { ProtocolTx::init(channel, state, p2p).await.unwrap() }
-            })
+    // Initialize syncing P2P network
+    let sync_p2p =
+        spawn_sync_p2p(&blockchain_config.sync_net.into(), &validator, &subscribers, ex.clone())
             .await;
             .await;
 
 
-        Some(p2p)
-    };
-
-    // P2P network settings for the consensus protocol
-    let consensus_p2p = {
-        if !args.consensus {
-            None
-        } else {
-            info!("Registering consensus P2P protocols...");
-            let consensus_network_settings = net::Settings {
-                inbound_addrs: args.consensus_p2p_accept,
-                outbound_connections: args.consensus_slots,
-                external_addrs: args.consensus_p2p_external,
-                peers: args.consensus_p2p_peer.clone(),
-                seeds: args.consensus_p2p_seed.clone(),
-                allowed_transports: args.consensus_p2p_transports,
-                localnet: args.localnet,
-                ..Default::default()
-            };
-            let p2p = net::P2p::new(consensus_network_settings, ex.clone()).await;
-            let registry = p2p.protocol_registry();
-
-            let _state = state.clone();
-            registry
-                .register(net::SESSION_ALL, move |channel, p2p| {
-                    let state = _state.clone();
-                    async move { ProtocolProposal::init(channel, state, p2p).await.unwrap() }
-                })
-                .await;
-
-            let _state = state.clone();
-            registry
-                .register(net::SESSION_ALL, move |channel, p2p| {
-                    let state = _state.clone();
-                    async move { ProtocolSyncConsensus::init(channel, state, p2p).await.unwrap() }
-                })
-                .await;
-
-            Some(p2p)
-        }
+    // Initialize consensus P2P network
+    let (consensus_p2p, rpc_client) = if blockchain_config.consensus {
+        let Ok(rpc_client) = RpcClient::new(blockchain_config.minerd_endpoint, ex.clone()).await
+        else {
+            error!(target: "darkfid", "Failed to initialize miner daemon rpc client, check if minerd is running");
+            return Err(Error::RpcClientStopped)
+        };
+        (
+            Some(
+                spawn_consensus_p2p(
+                    &blockchain_config.consensus_net.into(),
+                    &validator,
+                    &subscribers,
+                    ex.clone(),
+                )
+                .await,
+            ),
+            Some(rpc_client),
+        )
+    } else {
+        (None, None)
     };
     };
 
 
-    // Initialize program state
-    let darkfid =
-        Darkfid::new(state.clone(), consensus_p2p.clone(), sync_p2p.clone(), wallet.clone()).await;
+    // Initialize node
+    let darkfid = Darkfid::new(
+        sync_p2p.clone(),
+        consensus_p2p.clone(),
+        validator.clone(),
+        subscribers,
+        rpc_client,
+    )
+    .await;
     let darkfid = Arc::new(darkfid);
     let darkfid = Arc::new(darkfid);
+    info!(target: "darkfid", "Node initialized successfully!");
+
+    // Pinging minerd daemon to verify it listens
+    if blockchain_config.consensus {
+        if let Err(e) = darkfid.ping_miner_daemon().await {
+            error!(target: "darkfid", "Failed to ping miner daemon: {}", e);
+            return Err(Error::RpcClientStopped)
+        }
+    }
 
 
     // JSON-RPC server
     // JSON-RPC server
-    info!("Starting JSON-RPC server");
+    info!(target: "darkfid", "Starting JSON-RPC server");
+    // Here we create a task variable so we can manually close the
+    // task later. P2P tasks don't need this since it has its own
+    // stop() function to shut down, also terminating the task we
+    // created for it.
     let rpc_task = StoppableTask::new();
     let rpc_task = StoppableTask::new();
     let darkfid_ = darkfid.clone();
     let darkfid_ = darkfid.clone();
     rpc_task.clone().start(
     rpc_task.clone().start(
@@ -457,69 +339,81 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
         ex.clone(),
         ex.clone(),
     );
     );
 
 
-    info!("Starting sync P2P network");
-    sync_p2p.clone().unwrap().start().await?;
-
-    // TODO: I think this is not necessary anymore
-    //info!("Waiting for sync P2P outbound connections");
-    //sync_p2p.clone().unwrap().wait_for_outbound(ex.clone()).await?;
-
-    match block_sync_task(sync_p2p.clone().unwrap(), state.clone()).await {
-        Ok(()) => *darkfid.synced.lock().await = true,
-        Err(e) => error!("Failed syncing blockchain: {}", e),
-    }
+    info!(target: "darkfid", "Starting sync P2P network");
+    sync_p2p.clone().start().await?;
 
 
     // Consensus protocol
     // Consensus protocol
-    let proposal_task = if args.consensus && *darkfid.synced.lock().await {
-        info!("Starting consensus P2P network");
+    if blockchain_config.consensus {
+        info!(target: "darkfid", "Starting consensus P2P network");
         let consensus_p2p = consensus_p2p.clone().unwrap();
         let consensus_p2p = consensus_p2p.clone().unwrap();
         consensus_p2p.clone().start().await?;
         consensus_p2p.clone().start().await?;
+    } else {
+        info!(target: "darkfid", "Not starting consensus P2P network");
+    }
 
 
-        // TODO: I think this is not necessary anymore
-        //info!("Waiting for consensus P2P outbound connections");
-        //consensus_p2p.clone().unwrap().wait_for_outbound(ex.clone()).await?;
+    // Sync blockchain
+    if !blockchain_config.skip_sync {
+        sync_task(&darkfid).await?;
+    } else {
+        *darkfid.validator.synced.write().await = true;
+    }
+
+    // Clean node pending transactions
+    darkfid.validator.purge_pending_txs().await?;
+
+    // Consensus protocol
+    let consensus_task = if blockchain_config.consensus {
+        info!(target: "darkfid", "Starting consensus protocol task");
+        // Grab rewards recipient public key(address)
+        if blockchain_config.recipient.is_none() {
+            return Err(Error::ParseFailed("Recipient address missing"))
+        }
+        let recipient = match PublicKey::from_str(&blockchain_config.recipient.unwrap()) {
+            Ok(address) => address,
+            Err(_) => return Err(Error::InvalidAddress),
+        };
 
 
-        info!("Starting consensus protocol task");
         let task = StoppableTask::new();
         let task = StoppableTask::new();
         task.clone().start(
         task.clone().start(
-            proposal_task(consensus_p2p.clone(), sync_p2p.clone().unwrap(), state, ex.clone()),
+            // Weird hack to prevent lifetimes hell
+            async move { miner_task(&darkfid, &recipient).await },
             |res| async {
             |res| async {
                 match res {
                 match res {
-                    Ok(()) | Err(Error::ProposalTaskStopped) => { /* Do nothing */ }
-                    Err(e) => error!(target: "darkfid", "Failed starting proposal task: {}", e),
+                    Ok(()) | Err(Error::MinerTaskStopped) => { /* Do nothing */ }
+                    Err(e) => error!(target: "darkfid", "Failed starting miner task: {}", e),
                 }
                 }
             },
             },
-            Error::ProposalTaskStopped,
+            Error::MinerTaskStopped,
             ex.clone(),
             ex.clone(),
         );
         );
         Some(task)
         Some(task)
     } else {
     } else {
-        info!("Not starting consensus P2P network");
+        info!(target: "darkfid", "Not participating in consensus");
         None
         None
     };
     };
 
 
     // Signal handling for graceful termination.
     // Signal handling for graceful termination.
     let (signals_handler, signals_task) = SignalHandler::new(ex)?;
     let (signals_handler, signals_task) = SignalHandler::new(ex)?;
     signals_handler.wait_termination(signals_task).await?;
     signals_handler.wait_termination(signals_task).await?;
-    info!("Caught termination signal, cleaning up and exiting...");
+    info!(target: "darkfid", "Caught termination signal, cleaning up and exiting...");
 
 
     info!(target: "darkfid", "Stopping JSON-RPC server...");
     info!(target: "darkfid", "Stopping JSON-RPC server...");
     rpc_task.stop().await;
     rpc_task.stop().await;
 
 
     info!(target: "darkfid", "Stopping syncing P2P network...");
     info!(target: "darkfid", "Stopping syncing P2P network...");
-    sync_p2p.clone().unwrap().stop().await;
-
-    if let Some(task) = proposal_task {
-        info!(target: "darkfid", "Stopping proposal task...");
-        task.stop().await;
+    sync_p2p.stop().await;
 
 
+    if blockchain_config.consensus {
         info!(target: "darkfid", "Stopping consensus P2P network...");
         info!(target: "darkfid", "Stopping consensus P2P network...");
         consensus_p2p.unwrap().stop().await;
         consensus_p2p.unwrap().stop().await;
+
+        info!(target: "darkfid", "Stopping consensus task...");
+        consensus_task.unwrap().stop().await;
     }
     }
 
 
-    info!("Flushing sled database...");
+    info!(target: "darkfid", "Flushing sled database...");
     let flushed_bytes = sled_db.flush_async().await?;
     let flushed_bytes = sled_db.flush_async().await?;
-    info!("Flushed {} bytes", flushed_bytes);
+    info!(target: "darkfid", "Flushed {} bytes", flushed_bytes);
 
 
     Ok(())
     Ok(())
 }
 }

+ 0 - 0
bin/darkfid2/src/proto/mod.rs → bin/darkfid/src/proto/mod.rs


+ 0 - 0
bin/darkfid2/src/proto/protocol_block.rs → bin/darkfid/src/proto/protocol_block.rs


+ 0 - 0
bin/darkfid2/src/proto/protocol_proposal.rs → bin/darkfid/src/proto/protocol_proposal.rs


+ 0 - 0
bin/darkfid2/src/proto/protocol_sync.rs → bin/darkfid/src/proto/protocol_sync.rs


+ 0 - 0
bin/darkfid2/src/proto/protocol_tx.rs → bin/darkfid/src/proto/protocol_tx.rs


+ 0 - 0
bin/darkfid2/src/rpc.rs → bin/darkfid/src/rpc.rs


+ 80 - 41
bin/darkfid/src/rpc_blockchain.rs

@@ -16,10 +16,10 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
  */
 
 
-use std::str::FromStr;
+use std::{collections::HashMap, str::FromStr};
 
 
 use darkfi_sdk::crypto::ContractId;
 use darkfi_sdk::crypto::ContractId;
-use darkfi_serial::{deserialize, serialize};
+use darkfi_serial::{deserialize_async, serialize_async};
 use log::{debug, error};
 use log::{debug, error};
 use tinyjson::JsonValue;
 use tinyjson::JsonValue;
 
 
@@ -32,8 +32,7 @@ use darkfi::{
     util::encoding::base64,
     util::encoding::base64,
 };
 };
 
 
-use super::Darkfid;
-use crate::{server_error, RpcError};
+use crate::{server_error, Darkfid, RpcError};
 
 
 impl Darkfid {
 impl Darkfid {
     // RPCAPI:
     // RPCAPI:
@@ -48,7 +47,7 @@ impl Darkfid {
     //   struct serialized into base64.
     //   struct serialized into base64.
     //
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.get_slot", "params": ["0"], "id": 1}
     // --> {"jsonrpc": "2.0", "method": "blockchain.get_slot", "params": ["0"], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": "ABCD...", "id": 1}
+    // <-- {"jsonrpc": "2.0", "result": {...}, "id": 1}
     pub async fn blockchain_get_slot(&self, id: u16, params: JsonValue) -> JsonResult {
     pub async fn blockchain_get_slot(&self, id: u16, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 1 || !params[0].is_string() {
         if params.len() != 1 || !params[0].is_string() {
@@ -60,15 +59,10 @@ impl Darkfid {
             Err(_) => return JsonError::new(ParseError, None, id).into(),
             Err(_) => return JsonError::new(ParseError, None, id).into(),
         };
         };
 
 
-        let validator_state = self.validator_state.read().await;
-
-        let blocks = match validator_state.blockchain.get_blocks_by_slot(&[slot]) {
-            Ok(v) => {
-                drop(validator_state);
-                v
-            }
+        let blocks = match self.validator.blockchain.get_blocks_by_slot(&[slot]) {
+            Ok(v) => v,
             Err(e) => {
             Err(e) => {
-                error!("[RPC] blockchain.get_slot: Failed fetching block by slot: {}", e);
+                error!(target: "darkfid::rpc::blockchain_get_slot", "Failed fetching block by slot: {}", e);
                 return JsonError::new(InternalError, None, id).into()
                 return JsonError::new(InternalError, None, id).into()
             }
             }
         };
         };
@@ -77,7 +71,7 @@ impl Darkfid {
             return server_error(RpcError::UnknownSlot, id, None)
             return server_error(RpcError::UnknownSlot, id, None)
         }
         }
 
 
-        let block = base64::encode(&serialize(&blocks[0]));
+        let block = base64::encode(&serialize_async(&blocks[0]).await);
         JsonResponse::new(JsonValue::String(block), id).into()
         JsonResponse::new(JsonValue::String(block), id).into()
     }
     }
 
 
@@ -96,7 +90,7 @@ impl Darkfid {
     // <-- {"jsonrpc": "2.0", "result": "ABCD...", "id": 1}
     // <-- {"jsonrpc": "2.0", "result": "ABCD...", "id": 1}
     pub async fn blockchain_get_tx(&self, id: u16, params: JsonValue) -> JsonResult {
     pub async fn blockchain_get_tx(&self, id: u16, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         let params = params.get::<Vec<JsonValue>>().unwrap();
-        if params.len() != 1 || !params[0].is_string() {
+        if params.len() != 1 {
             return JsonError::new(InvalidParams, None, id).into()
             return JsonError::new(InvalidParams, None, id).into()
         }
         }
 
 
@@ -106,25 +100,19 @@ impl Darkfid {
             Err(_) => return JsonError::new(ParseError, None, id).into(),
             Err(_) => return JsonError::new(ParseError, None, id).into(),
         };
         };
 
 
-        let validator_state = self.validator_state.read().await;
-
-        let txs = match validator_state.blockchain.transactions.get(&[tx_hash], true) {
-            Ok(txs) => {
-                drop(validator_state);
-                txs
-            }
+        let txs = match self.validator.blockchain.transactions.get(&[tx_hash], true) {
+            Ok(txs) => txs,
             Err(e) => {
             Err(e) => {
-                error!("[RPC] blockchain.get_tx: Failed fetching tx by hash: {}", e);
+                error!(target: "darkfid::rpc::blockchain_get_tx", "Failed fetching tx by hash: {}", e);
                 return JsonError::new(InternalError, None, id).into()
                 return JsonError::new(InternalError, None, id).into()
             }
             }
         };
         };
-
         // This would be an logic error somewhere
         // This would be an logic error somewhere
         assert_eq!(txs.len(), 1);
         assert_eq!(txs.len(), 1);
         // and strict was used during .get()
         // and strict was used during .get()
         let tx = txs[0].as_ref().unwrap();
         let tx = txs[0].as_ref().unwrap();
 
 
-        let tx_enc = base64::encode(&serialize(tx));
+        let tx_enc = base64::encode(&serialize_async(tx).await);
         JsonResponse::new(JsonValue::String(tx_enc), id).into()
         JsonResponse::new(JsonValue::String(tx_enc), id).into()
     }
     }
 
 
@@ -145,12 +133,12 @@ impl Darkfid {
             return JsonError::new(InvalidParams, None, id).into()
             return JsonError::new(InvalidParams, None, id).into()
         }
         }
 
 
-        let blockchain = { self.validator_state.read().await.blockchain.clone() };
+        let blockchain = self.validator.blockchain.clone();
         let Ok(last_slot) = blockchain.last() else {
         let Ok(last_slot) = blockchain.last() else {
             return JsonError::new(InternalError, None, id).into()
             return JsonError::new(InternalError, None, id).into()
         };
         };
 
 
-        JsonResponse::new(JsonValue::String(last_slot.0.to_string()), id).into()
+        JsonResponse::new(JsonValue::Number(last_slot.0 as f64), id).into()
     }
     }
 
 
     // RPCAPI:
     // RPCAPI:
@@ -166,23 +154,47 @@ impl Darkfid {
             return JsonError::new(InvalidParams, None, id).into()
             return JsonError::new(InvalidParams, None, id).into()
         }
         }
 
 
-        self.validator_state.read().await.subscribers.get("blocks").unwrap().clone().into()
+        self.subscribers.get("blocks").unwrap().clone().into()
     }
     }
 
 
     // RPCAPI:
     // RPCAPI:
-    // Initializes a subscription to erroneous transactions notifications.
+    // Initializes a subscription to new incoming transactions.
     // Once a subscription is established, `darkfid` will send JSON-RPC notifications of
     // Once a subscription is established, `darkfid` will send JSON-RPC notifications of
-    // erroneous transactions to the subscriber.
+    // new incoming transactions to the subscriber.
     //
     //
-    // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_err_txs", "params": [], "id": 1}
-    // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_err_txs", "params": [`tx_hash`]}
-    pub async fn blockchain_subscribe_err_txs(&self, id: u16, params: JsonValue) -> JsonResult {
+    // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_txs", "params": [], "id": 1}
+    // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_txs", "params": [`tx_hash`]}
+    pub async fn blockchain_subscribe_txs(&self, id: u16, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.is_empty() {
         if !params.is_empty() {
             return JsonError::new(InvalidParams, None, id).into()
             return JsonError::new(InvalidParams, None, id).into()
         }
         }
 
 
-        self.validator_state.read().await.subscribers.get("err_txs").unwrap().clone().into()
+        self.subscribers.get("txs").unwrap().clone().into()
+    }
+
+    // RPCAPI:
+    // Initializes a subscription to new incoming proposals, asuming node participates
+    // in consensus. Once a subscription is established, `darkfid` will send JSON-RPC
+    // notifications of new incoming proposals to the subscriber.
+    //
+    // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_proposals", "params": [], "id": 1}
+    // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_proposals", "params": [`blockinfo`]}
+    pub async fn blockchain_subscribe_proposals(&self, id: u16, params: JsonValue) -> JsonResult {
+        let params = params.get::<Vec<JsonValue>>().unwrap();
+        if !params.is_empty() {
+            return JsonError::new(InvalidParams, None, id).into()
+        }
+
+        // Since proposals subscriber is only active if we participate to consensus,
+        // we have to check if it actually exists in the subscribers map.
+        let proposals_subscriber = self.subscribers.get("proposals");
+        if proposals_subscriber.is_none() {
+            error!(target: "darkfid::rpc::blockchain_subscribe_proposals", "Proposals subscriber not found");
+            return JsonError::new(InternalError, None, id).into()
+        }
+
+        proposals_subscriber.unwrap().clone().into()
     }
     }
 
 
     // RPCAPI:
     // RPCAPI:
@@ -193,7 +205,7 @@ impl Darkfid {
     // * `array[0]`: base58-encoded contract ID string
     // * `array[0]`: base58-encoded contract ID string
     //
     //
     // **Returns:**
     // **Returns:**
-    // * `array[n]`: Pairs of: `zkas_namespace` string, serialized and base64-encoded
+    // * `array[n]`: Pairs of: `zkas_namespace` string, serialized
     //   [`ZkBinary`](https://darkrenaissance.github.io/darkfi/development/darkfi/zkas/decoder/struct.ZkBinary.html)
     //   [`ZkBinary`](https://darkrenaissance.github.io/darkfi/development/darkfi/zkas/decoder/struct.ZkBinary.html)
     //   object
     //   object
     //
     //
@@ -209,12 +221,12 @@ impl Darkfid {
         let contract_id = match ContractId::from_str(contract_id) {
         let contract_id = match ContractId::from_str(contract_id) {
             Ok(v) => v,
             Ok(v) => v,
             Err(e) => {
             Err(e) => {
-                error!("[RPC] blockchain.lookup_zkas: Error decoding string to ContractId: {}", e);
+                error!(target: "darkfid::rpc::blockchain_lookup_zkas", "Error decoding string to ContractId: {}", e);
                 return JsonError::new(InvalidParams, None, id).into()
                 return JsonError::new(InvalidParams, None, id).into()
             }
             }
         };
         };
 
 
-        let blockchain = { self.validator_state.read().await.blockchain.clone() };
+        let blockchain = self.validator.blockchain.clone();
 
 
         let Ok(zkas_db) = blockchain.contracts.lookup(
         let Ok(zkas_db) = blockchain.contracts.lookup(
             &blockchain.sled_db,
             &blockchain.sled_db,
@@ -222,7 +234,7 @@ impl Darkfid {
             SMART_CONTRACT_ZKAS_DB_NAME,
             SMART_CONTRACT_ZKAS_DB_NAME,
         ) else {
         ) else {
             error!(
             error!(
-                "[RPC] blockchain.lookup_zkas: Did not find zkas db for ContractId: {}",
+                target: "darkfid::rpc::blockchain_lookup_zkas", "Did not find zkas db for ContractId: {}",
                 contract_id
                 contract_id
             );
             );
             return server_error(RpcError::ContractZkasDbNotFound, id, None)
             return server_error(RpcError::ContractZkasDbNotFound, id, None)
@@ -231,13 +243,13 @@ impl Darkfid {
         let mut ret = vec![];
         let mut ret = vec![];
 
 
         for i in zkas_db.iter() {
         for i in zkas_db.iter() {
-            debug!("Iterating over zkas db");
+            debug!(target: "darkfid::rpc::blockchain_lookup_zkas", "Iterating over zkas db");
             let Ok((zkas_ns, zkas_bytes)) = i else {
             let Ok((zkas_ns, zkas_bytes)) = i else {
-                error!("Internal sled error iterating db");
+                error!(target: "darkfid::rpc::blockchain_lookup_zkas", "Internal sled error iterating db");
                 return JsonError::new(InternalError, None, id).into()
                 return JsonError::new(InternalError, None, id).into()
             };
             };
 
 
-            let Ok(zkas_ns) = deserialize(&zkas_ns) else {
+            let Ok(zkas_ns) = deserialize_async(&zkas_ns).await else {
                 return JsonError::new(InternalError, None, id).into()
                 return JsonError::new(InternalError, None, id).into()
             };
             };
 
 
@@ -250,4 +262,31 @@ impl Darkfid {
 
 
         JsonResponse::new(JsonValue::Array(ret), id).into()
         JsonResponse::new(JsonValue::Array(ret), id).into()
     }
     }
+
+    // RPCAPI:
+    // Returns the `chain_id` used for merge mining. A 32-byte hash of the genesis block.
+    //
+    // --> {"jsonrpc": "2.0", "method": "merge_mining_get_chain_id", "params": [], "id": 0}
+    // <-- {"jsonrpc": "2.0", "result": {"chain_id": 02f8...7863"}, "id": 0}
+    pub async fn merge_mining_get_chain_id(&self, id: u16, _params: JsonValue) -> JsonResult {
+        let chain_id = match self.validator.blockchain.genesis() {
+            Ok((_, v)) => v,
+            Err(e) => {
+                error!(
+                    target: "darkfid::rpc::merge_mining_get_chain_id",
+                    "[RPC] Error looking up genesis block: {}", e,
+                );
+                return JsonError::new(InternalError, None, id).into()
+            }
+        };
+
+        JsonResponse::new(
+            JsonValue::Object(HashMap::from([(
+                "chain_id".to_string(),
+                chain_id.to_hex().to_string().into(),
+            )])),
+            id,
+        )
+        .into()
+    }
 }
 }

+ 0 - 85
bin/darkfid/src/rpc_misc.rs

@@ -1,85 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use tinyjson::JsonValue;
-
-use darkfi::{
-    rpc::jsonrpc::{ErrorCode, JsonError, JsonResponse, JsonResult},
-    util::time::Timestamp,
-};
-
-use super::Darkfid;
-
-impl Darkfid {
-    // RPCAPI:
-    // Returns current system clock as u64 (string) timestamp
-    //
-    // --> {"jsonrpc": "2.0", "method": "clock", "params": [], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": "1234"}, "id": 1}
-    pub async fn misc_clock(&self, id: u16, _params: JsonValue) -> JsonResult {
-        JsonResponse::new(JsonValue::String(Timestamp::current_time().0.to_string()), id).into()
-    }
-
-    // RPCAPI:
-    // Activate or deactivate dnet in the sync P2P stack.
-    // By sending `true`, dnet will be activated, and by sending `false` dnet
-    // will be deactivated. Returns `true` on success.
-    //
-    // --> {"jsonrpc": "2.0", "method": "sync_dnet_switch", "params": [true], "id": 42}
-    // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    pub async fn misc_sync_dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if params.len() != 1 || !params[0].is_bool() {
-            return JsonError::new(ErrorCode::InvalidParams, None, id).into()
-        }
-
-        let switch = params[0].get::<bool>().unwrap();
-
-        if *switch {
-            self.sync_p2p.as_ref().unwrap().dnet_enable().await;
-        } else {
-            self.sync_p2p.as_ref().unwrap().dnet_disable().await;
-        }
-
-        JsonResponse::new(JsonValue::Boolean(true), id).into()
-    }
-
-    // RPCAPI:
-    // Activate or deactivate dnet in the consensus P2P stack.
-    // By sending `true`, dnet will be activated, and by sending `false` dnet
-    // will be deactivated. Returns `true` on success.
-    //
-    // --> {"jsonrpc": "2.0", "method": "consensus_dnet_switch", "params": [true], "id": 42}
-    // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    pub async fn misc_consensus_dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if params.len() != 1 || !params[0].is_bool() {
-            return JsonError::new(ErrorCode::InvalidParams, None, id).into()
-        }
-
-        let switch = params[0].get::<bool>().unwrap();
-
-        if *switch {
-            self.consensus_p2p.as_ref().unwrap().dnet_enable().await;
-        } else {
-            self.consensus_p2p.as_ref().unwrap().dnet_disable().await;
-        }
-
-        JsonResponse::new(JsonValue::Boolean(true), id).into()
-    }
-}

+ 114 - 58
bin/darkfid/src/rpc_tx.rs

@@ -16,12 +16,15 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
  */
 
 
-use darkfi_serial::deserialize;
-use log::{error, warn};
+use darkfi_serial::deserialize_async;
+use log::error;
 use tinyjson::JsonValue;
 use tinyjson::JsonValue;
 
 
 use darkfi::{
 use darkfi::{
-    rpc::jsonrpc::{ErrorCode::InvalidParams, JsonError, JsonResponse, JsonResult},
+    rpc::jsonrpc::{
+        ErrorCode::{InternalError, InvalidParams},
+        JsonError, JsonResponse, JsonResult,
+    },
     tx::Transaction,
     tx::Transaction,
     util::encoding::base64,
     util::encoding::base64,
 };
 };
@@ -35,7 +38,7 @@ impl Darkfid {
     // Returns `true` if the transaction is valid, otherwise, a corresponding
     // Returns `true` if the transaction is valid, otherwise, a corresponding
     // error.
     // error.
     //
     //
-    // --> {"jsonrpc": "2.0", "method": "tx.simulate", "params": ["base58encodedTX"], "id": 1}
+    // --> {"jsonrpc": "2.0", "method": "tx.simulate", "params": ["base64encodedTX"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
     pub async fn tx_simulate(&self, id: u16, params: JsonValue) -> JsonResult {
     pub async fn tx_simulate(&self, id: u16, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         let params = params.get::<Vec<JsonValue>>().unwrap();
@@ -43,43 +46,38 @@ impl Darkfid {
             return JsonError::new(InvalidParams, None, id).into()
             return JsonError::new(InvalidParams, None, id).into()
         }
         }
 
 
-        if !(*self.synced.lock().await) {
-            error!("[RPC] tx.simulate: Blockchain is not synced");
+        if !*self.validator.synced.read().await {
+            error!(target: "darkfid::rpc::tx_simulate", "Blockchain is not synced");
             return server_error(RpcError::NotSynced, id, None)
             return server_error(RpcError::NotSynced, id, None)
         }
         }
 
 
         // Try to deserialize the transaction
         // Try to deserialize the transaction
-        let tx_enc = params[0].get::<String>().unwrap();
-        let tx_bytes = match base64::decode(tx_enc.trim()) {
+        let tx_enc = params[0].get::<String>().unwrap().trim();
+        let tx_bytes = match base64::decode(tx_enc) {
             Some(v) => v,
             Some(v) => v,
             None => {
             None => {
-                error!("[RPC] tx.simulate: Failed decoding base64 transaction");
+                error!(target: "darkfid::rpc::tx_simulate", "Failed decoding base64 transaction");
                 return server_error(RpcError::ParseError, id, None)
                 return server_error(RpcError::ParseError, id, None)
             }
             }
         };
         };
 
 
-        let tx: Transaction = match deserialize(&tx_bytes) {
+        let tx: Transaction = match deserialize_async(&tx_bytes).await {
             Ok(v) => v,
             Ok(v) => v,
             Err(e) => {
             Err(e) => {
-                error!("[RPC] tx.simulate: Failed deserializing bytes into Transaction: {}", e);
+                error!(target: "darkfid::rpc::tx_simulate", "Failed deserializing bytes into Transaction: {}", e);
                 return server_error(RpcError::ParseError, id, None)
                 return server_error(RpcError::ParseError, id, None)
             }
             }
         };
         };
 
 
         // Simulate state transition
         // Simulate state transition
-        let lock = self.validator_state.read().await;
-        let current_slot = lock.consensus.time_keeper.current_slot();
-        match lock.verify_transactions(&[tx], current_slot, false).await {
-            Ok(erroneous_txs) => {
-                if !erroneous_txs.is_empty() {
-                    error!("[RPC] tx.simulate: invalid transaction provided");
-                    return server_error(RpcError::TxSimulationFail, id, None)
-                }
-            }
-            Err(e) => {
-                error!("[RPC] tx.simulate: Failed to validate state transition: {}", e);
-                return server_error(RpcError::TxSimulationFail, id, None)
-            }
+        let current_slot = self.validator.consensus.time_keeper.current_slot();
+        let result = self.validator.add_transactions(&[tx], current_slot, false).await;
+        if result.is_err() {
+            error!(
+                target: "darkfid::rpc::tx_simulate", "Failed to validate state transition: {}",
+                result.err().unwrap()
+            );
+            return server_error(RpcError::TxSimulationFail, id, None)
         };
         };
 
 
         JsonResponse::new(JsonValue::Boolean(true), id).into()
         JsonResponse::new(JsonValue::Boolean(true), id).into()
@@ -91,7 +89,7 @@ impl Darkfid {
     // if the transaction is actually valid, and in turn it will return an
     // if the transaction is actually valid, and in turn it will return an
     // error if this is the case. Otherwise, a transaction ID will be returned.
     // error if this is the case. Otherwise, a transaction ID will be returned.
     //
     //
-    // --> {"jsonrpc": "2.0", "method": "tx.broadcast", "params": ["base58encodedTX"], "id": 1}
+    // --> {"jsonrpc": "2.0", "method": "tx.broadcast", "params": ["base64encodedTX"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": "txID...", "id": 1}
     // <-- {"jsonrpc": "2.0", "result": "txID...", "id": 1}
     pub async fn tx_broadcast(&self, id: u16, params: JsonValue) -> JsonResult {
     pub async fn tx_broadcast(&self, id: u16, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         let params = params.get::<Vec<JsonValue>>().unwrap();
@@ -99,66 +97,124 @@ impl Darkfid {
             return JsonError::new(InvalidParams, None, id).into()
             return JsonError::new(InvalidParams, None, id).into()
         }
         }
 
 
-        if !(*self.synced.lock().await) {
-            error!("[RPC] tx.transfer: Blockchain is not synced");
+        if !*self.validator.synced.read().await {
+            error!(target: "darkfid::rpc::tx_broadcast", "Blockchain is not synced");
             return server_error(RpcError::NotSynced, id, None)
             return server_error(RpcError::NotSynced, id, None)
         }
         }
 
 
         // Try to deserialize the transaction
         // Try to deserialize the transaction
-        let tx_enc = params[0].get::<String>().unwrap();
-        let tx_bytes = match base64::decode(tx_enc.trim()) {
+        let tx_enc = params[0].get::<String>().unwrap().trim();
+        let tx_bytes = match base64::decode(tx_enc) {
             Some(v) => v,
             Some(v) => v,
             None => {
             None => {
-                error!("[RPC] tx.broadcast: Failed decoding base64 transaction");
+                error!(target: "darkfid::rpc::tx_broadcast", "Failed decoding base64 transaction");
                 return server_error(RpcError::ParseError, id, None)
                 return server_error(RpcError::ParseError, id, None)
             }
             }
         };
         };
 
 
-        let tx: Transaction = match deserialize(&tx_bytes) {
+        let tx: Transaction = match deserialize_async(&tx_bytes).await {
             Ok(v) => v,
             Ok(v) => v,
             Err(e) => {
             Err(e) => {
-                error!("[RPC] tx.broadcast: Failed deserializing bytes into Transaction: {}", e);
+                error!(target: "darkfid::rpc::tx_broadcast", "Failed deserializing bytes into Transaction: {}", e);
                 return server_error(RpcError::ParseError, id, None)
                 return server_error(RpcError::ParseError, id, None)
             }
             }
         };
         };
 
 
         if self.consensus_p2p.is_some() {
         if self.consensus_p2p.is_some() {
-            // Consider we're participating in consensus here?
-            // The append_tx function performs a state transition check.
-            if !self.validator_state.write().await.append_tx(tx.clone()).await {
-                error!("[RPC] tx.broadcast: Failed to append transaction to mempool");
-                return server_error(RpcError::TxBroadcastFail, id, None)
+            // Consensus participants can directly perform
+            // the state transition check and append to their
+            // pending transactions store.
+            if self.validator.append_tx(&tx).await.is_err() {
+                error!(target: "darkfid::rpc::tx_broadcast", "Failed to append transaction to mempool");
+                return server_error(RpcError::TxSimulationFail, id, None)
             }
             }
         } else {
         } else {
             // We'll perform the state transition check here.
             // We'll perform the state transition check here.
-            let lock = self.validator_state.read().await;
-            let current_slot = lock.consensus.time_keeper.current_slot();
-            match lock.verify_transactions(&[tx.clone()], current_slot, false).await {
-                Ok(erroneous_txs) => {
-                    if !erroneous_txs.is_empty() {
-                        error!("[RPC] tx.broadcast: invalid transaction provided");
-                        return server_error(RpcError::TxSimulationFail, id, None)
-                    }
-                }
-                Err(e) => {
-                    error!("[RPC] tx.broadcast: Failed to validate state transition: {}", e);
-                    return server_error(RpcError::TxSimulationFail, id, None)
-                }
+            let current_slot = self.validator.consensus.time_keeper.current_slot();
+            let result = self.validator.add_transactions(&[tx.clone()], current_slot, false).await;
+            if result.is_err() {
+                error!(
+                    target: "darkfid::rpc::tx_broadcast", "Failed to validate state transition: {}",
+                    result.err().unwrap()
+                );
+                return server_error(RpcError::TxSimulationFail, id, None)
             };
             };
         }
         }
 
 
-        if let Some(sync_p2p) = &self.sync_p2p {
-            sync_p2p.broadcast(&tx).await;
-            if sync_p2p.channels().await.is_empty() {
-                error!("[RPC] tx.broadcast: Failed broadcasting tx, no connected channels");
-                return server_error(RpcError::TxBroadcastFail, id, None)
-            }
-        } else {
-            warn!("[RPC] tx.broadcast: No sync P2P network, not broadcasting transaction.");
+        self.sync_p2p.broadcast(&tx).await;
+        if self.sync_p2p.channels().await.is_empty() {
+            error!(target: "darkfid::rpc::tx_broadcast", "Failed broadcasting tx, no connected channels");
             return server_error(RpcError::TxBroadcastFail, id, None)
             return server_error(RpcError::TxBroadcastFail, id, None)
         }
         }
 
 
         let tx_hash = tx.hash().unwrap().to_string();
         let tx_hash = tx.hash().unwrap().to_string();
         JsonResponse::new(JsonValue::String(tx_hash), id).into()
         JsonResponse::new(JsonValue::String(tx_hash), id).into()
     }
     }
+
+    // RPCAPI:
+    // Queries the node pending transactions store to retrieve all transactions.
+    // Returns a vector of hex-encoded transaction hashes.
+    //
+    // --> {"jsonrpc": "2.0", "method": "tx.pending", "params": [], "id": 1}
+    // <-- {"jsonrpc": "2.0", "result": "[TxHash,...]", "id": 1}
+    pub async fn tx_pending(&self, id: u16, params: JsonValue) -> JsonResult {
+        let params = params.get::<Vec<JsonValue>>().unwrap();
+        if !params.is_empty() {
+            return JsonError::new(InvalidParams, None, id).into()
+        }
+
+        if !*self.validator.synced.read().await {
+            error!(target: "darkfid::rpc::tx_pending", "Blockchain is not synced");
+            return server_error(RpcError::NotSynced, id, None)
+        }
+
+        let pending_txs = match self.validator.blockchain.get_pending_txs() {
+            Ok(v) => v,
+            Err(e) => {
+                error!(target: "darkfid::rpc::tx_pending", "Failed fetching pending txs: {}", e);
+                return JsonError::new(InternalError, None, id).into()
+            }
+        };
+
+        let pending_txs: Vec<JsonValue> =
+            pending_txs.iter().map(|x| JsonValue::String(x.hash().unwrap().to_string())).collect();
+
+        JsonResponse::new(JsonValue::Array(pending_txs), id).into()
+    }
+
+    // RPCAPI:
+    // Queries the node pending transactions store to remove all transactions.
+    // Returns a vector of hex-encoded transaction hashes.
+    //
+    // --> {"jsonrpc": "2.0", "method": "tx.clean_pending", "params": [], "id": 1}
+    // <-- {"jsonrpc": "2.0", "result": "[TxHash,...]", "id": 1}
+    pub async fn tx_clean_pending(&self, id: u16, params: JsonValue) -> JsonResult {
+        let params = params.get::<Vec<JsonValue>>().unwrap();
+        if !params.is_empty() {
+            return JsonError::new(InvalidParams, None, id).into()
+        }
+
+        if !*self.validator.synced.read().await {
+            error!(target: "darkfid::rpc::tx_clean_pending", "Blockchain is not synced");
+            return server_error(RpcError::NotSynced, id, None)
+        }
+
+        let pending_txs = match self.validator.blockchain.get_pending_txs() {
+            Ok(v) => v,
+            Err(e) => {
+                error!(target: "darkfid::rpc::tx_clean_pending", "Failed fetching pending txs: {}", e);
+                return JsonError::new(InternalError, None, id).into()
+            }
+        };
+
+        if let Err(e) = self.validator.blockchain.remove_pending_txs(&pending_txs) {
+            error!(target: "darkfid::rpc::tx_clean_pending", "Failed fetching pending txs: {}", e);
+            return JsonError::new(InternalError, None, id).into()
+        };
+
+        let pending_txs: Vec<JsonValue> =
+            pending_txs.iter().map(|x| JsonValue::String(x.hash().unwrap().to_string())).collect();
+
+        JsonResponse::new(JsonValue::Array(pending_txs), id).into()
+    }
 }
 }

+ 0 - 441
bin/darkfid/src/rpc_wallet.rs

@@ -1,441 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-/*
-use log::{debug, error};
-use serde_json::{json, Value};
-
-use darkfi::{
-    rpc::jsonrpc::{
-        ErrorCode::{InternalError, InvalidParams, ParseError},
-        JsonError, JsonResponse, JsonResult,
-    },
-    wallet::walletdb::QueryType,
-};
-
-use super::{error::RpcError, server_error, Darkfid};
-*/
-use darkfi::rpc::jsonrpc::JsonResult;
-use tinyjson::JsonValue;
-
-use super::Darkfid;
-
-impl Darkfid {
-    // RPCAPI:
-    // Attempts to query for a single row in a given table.
-    // The parameters given contain paired metadata so we know how to decode the SQL data.
-    // An example of `params` is as such:
-    // ```
-    // params[0] -> "sql query"
-    // params[1] -> column_type
-    // params[2] -> "column_name"
-    // ...
-    // params[n-1] -> column_type
-    // params[n] -> "column_name"
-    // ```
-    // This function will fetch the first row it finds, if any. The `column_type` field
-    // is a type available in the `WalletDb` API as an enum called `QueryType`. If a row
-    // is not found, the returned result will be a JSON-RPC error.
-    // NOTE: This is obviously vulnerable to SQL injection. Open to interesting solutions.
-    //
-    // --> {"jsonrpc": "2.0", "method": "wallet.query_row_single", "params": [...], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": ["va", "lu", "es", ...], "id": 1}
-    pub async fn wallet_query_row_single(&self, _id: u16, _params: JsonValue) -> JsonResult {
-        todo!();
-        /* TODO: This will be abstracted away
-        // We need at least 3 params for something we want to fetch, and we want them in pairs.
-        // Also the first param should be a String
-        if params.len() < 3 || params[1..].len() % 2 != 0 || !params[0].is_string() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        // The remaining pairs should be typed properly too
-        let mut types: Vec<QueryType> = vec![];
-        let mut names: Vec<&str> = vec![];
-        for pair in params[1..].chunks(2) {
-            if !pair[0].is_u64() || !pair[1].is_string() {
-                return JsonError::new(InvalidParams, None, id).into()
-            }
-
-            let typ = pair[0].as_u64().unwrap();
-            if typ >= QueryType::Last as u64 {
-                return JsonError::new(InvalidParams, None, id).into()
-            }
-
-            types.push((typ as u8).into());
-            names.push(pair[1].as_str().unwrap());
-        }
-
-        // Get a wallet connection
-        let mut conn = match self.wallet.conn.acquire().await {
-            Ok(v) => v,
-            Err(e) => {
-                error!("[RPC] wallet.query_row_single: Failed to acquire wallet connection: {}", e);
-                return JsonError::new(InternalError, None, id).into()
-            }
-        };
-
-        // Execute the query and see if we find a row
-        let row = match sqlx::query(params[0].as_str().unwrap()).fetch_one(&mut conn).await {
-            Ok(v) => Some(v),
-            Err(_) => None,
-        };
-
-        // Try to decode the row into what was requested
-        let mut ret: Vec<Value> = vec![];
-
-        for (typ, col) in types.iter().zip(names) {
-            match typ {
-                QueryType::Integer => {
-                    let Some(ref row) = row else {
-                        error!("[RPC] wallet.query_row_single: Got None for QueryType::Integer");
-                        return server_error(RpcError::NoRowsFoundInWallet, id, None)
-                    };
-
-                    let value: i32 = match row.try_get(col) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!("[RPC] wallet.query_row_single: {}", e);
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    ret.push(json!(value));
-                    continue
-                }
-
-                QueryType::Blob => {
-                    let Some(ref row) = row else {
-                        error!("[RPC] wallet.query_row_single: Got None for QueryType::Blob");
-                        return server_error(RpcError::NoRowsFoundInWallet, id, None)
-                    };
-
-                    let value: Vec<u8> = match row.try_get(col) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!("[RPC] wallet.query_row_single: {}", e);
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    ret.push(json!(value));
-                    continue
-                }
-
-                QueryType::OptionInteger => {
-                    let Some(ref row) = row else {
-                        ret.push(json!(None::<i32>));
-                        continue
-                    };
-
-                    let value: i32 = match row.try_get(col) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!("[RPC] wallet.query_row_single: {}", e);
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    ret.push(json!(value));
-                    continue
-                }
-
-                QueryType::OptionBlob => {
-                    let Some(ref row) = row else {
-                        ret.push(json!(None::<Vec<u8>>));
-                        continue
-                    };
-
-                    let value: Vec<u8> = match row.try_get(col) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!("[RPC] wallet.query_row_single: {}", e);
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    ret.push(json!(value));
-                    continue
-                }
-
-                QueryType::Text => {
-                    let Some(ref row) = row else {
-                        error!("[RPC] wallet.query_row_single: Got None for QueryType::Text");
-                        return server_error(RpcError::NoRowsFoundInWallet, id, None)
-                    };
-
-                    let value: String = match row.try_get(col) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!("[RPC] wallet.query_row_single: {}", e);
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    ret.push(json!(value));
-                    continue
-                }
-
-                _ => unreachable!(),
-            }
-        }
-
-        JsonResponse::new(json!(ret), id).into()
-        */
-    }
-
-    // RPCAPI:
-    // Attempts to query for all available rows in a given table.
-    // The parameters given contain paired metadata so we know how to decode the SQL data.
-    // They're the same as above in `wallet.query_row_single`.
-    // If there are any values found, they will be returned in a paired array. If not, an
-    // empty array will be returned.
-    //
-    // --> {"jsonrpc": "2.0", "method": "wallet.query_row_multi", "params": [...], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": [["va", "lu"], ["es", "es"], ...], "id": 1}
-    pub async fn wallet_query_row_multi(&self, _id: u16, _params: JsonValue) -> JsonResult {
-        todo!();
-        /* TODO: This will be abstracted away
-        // We need at least 3 params for something we want to fetch, and we want them in pairs.
-        // Also the first param (the query) should be a String.
-        if params.len() < 3 || params[1..].len() % 2 != 0 || !params[0].is_string() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        // The remaining pairs should be typed properly too
-        let mut types: Vec<QueryType> = vec![];
-        let mut names: Vec<&str> = vec![];
-        for pair in params[1..].chunks(2) {
-            if !pair[0].is_u64() || !pair[1].is_string() {
-                return JsonError::new(InvalidParams, None, id).into()
-            }
-
-            let typ = pair[0].as_u64().unwrap();
-            if typ >= QueryType::Last as u64 {
-                return JsonError::new(InvalidParams, None, id).into()
-            }
-
-            types.push((typ as u8).into());
-            names.push(pair[1].as_str().unwrap());
-        }
-
-        // Get a wallet connection
-        let mut conn = match self.wallet.conn.acquire().await {
-            Ok(v) => v,
-            Err(e) => {
-                error!("[RPC] wallet.query_row_multi: Failed to acquire wallet connection: {}", e);
-                return JsonError::new(InternalError, None, id).into()
-            }
-        };
-
-        // Execute the query and see if we find any rows
-        let rows = match sqlx::query(params[0].as_str().unwrap()).fetch_all(&mut conn).await {
-            Ok(v) => v,
-            Err(e) => {
-                error!("[RPC] wallet.query_row_multi: Failed to execute SQL query: {}", e);
-                return JsonError::new(InternalError, None, id).into()
-            }
-        };
-
-        debug!("[RPC] wallet.query_row_multi: Found {} rows", rows.len());
-
-        // Try to decode whatever we've found
-        let mut ret: Vec<Vec<Value>> = vec![];
-
-        for row in rows {
-            let mut row_ret: Vec<Value> = vec![];
-            for (typ, col) in types.iter().zip(names.clone()) {
-                match typ {
-                    QueryType::Integer => {
-                        let value: i32 = match row.try_get(col) {
-                            Ok(v) => v,
-                            Err(e) => {
-                                error!("[RPC] wallet.query_row_multi: {}", e);
-                                return JsonError::new(ParseError, None, id).into()
-                            }
-                        };
-
-                        row_ret.push(json!(value));
-                    }
-
-                    QueryType::Blob => {
-                        let value: Vec<u8> = match row.try_get(col) {
-                            Ok(v) => v,
-                            Err(e) => {
-                                error!("[RPC] wallet.query_row_multi: {}", e);
-                                return JsonError::new(ParseError, None, id).into()
-                            }
-                        };
-
-                        row_ret.push(json!(value));
-                    }
-
-                    QueryType::OptionInteger => {
-                        let value: Option<i32> = match row.try_get(col) {
-                            Ok(v) => Some(v),
-                            Err(_) => None,
-                        };
-
-                        row_ret.push(json!(value));
-                    }
-
-                    QueryType::OptionBlob => {
-                        let value: Option<Vec<u8>> = match row.try_get(col) {
-                            Ok(v) => Some(v),
-                            Err(_) => None,
-                        };
-
-                        row_ret.push(json!(value));
-                    }
-
-                    QueryType::Text => {
-                        let value: String = match row.try_get(col) {
-                            Ok(v) => v,
-                            Err(e) => {
-                                error!("[RPC] wallet.query_row_multi: {}", e);
-                                return JsonError::new(ParseError, None, id).into()
-                            }
-                        };
-
-                        row_ret.push(json!(value));
-                    }
-
-                    _ => unreachable!(),
-                }
-            }
-
-            ret.push(row_ret);
-        }
-
-        JsonResponse::new(json!(ret), id).into()
-        */
-    }
-
-    // RPCAPI:
-    // Executes an arbitrary SQL query on the wallet, and returns `true` on success.
-    // `params[1..]` can optionally be provided in pairs like in `wallet.query_row_single`.
-    //
-    // --> {"jsonrpc": "2.0", "method": "wallet.exec_sql", "params": ["CREATE TABLE ..."], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
-    pub async fn wallet_exec_sql(&self, _id: u16, _params: JsonValue) -> JsonResult {
-        todo!();
-        /* TODO: This will be abstracted away
-        if params.is_empty() || !params[0].is_string() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        if params.len() > 1 && params[1..].len() % 2 != 0 {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        let query = params[0].as_str().unwrap();
-        debug!("Executing SQL query: {}", query);
-        let mut query = sqlx::query(query);
-
-        for pair in params[1..].chunks(2) {
-            if !pair[0].is_u64() || pair[0].as_u64().unwrap() >= QueryType::Last as u64 {
-                return JsonError::new(InvalidParams, None, id).into()
-            }
-
-            let typ = (pair[0].as_u64().unwrap() as u8).into();
-            match typ {
-                QueryType::Integer => {
-                    let val: i32 = match serde_json::from_value(pair[1].clone()) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!("[RPC] wallet.exec_sql: Failed casting value to i32: {}", e);
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    query = query.bind(val);
-                }
-
-                QueryType::Blob => {
-                    let val: Vec<u8> = match serde_json::from_value(pair[1].clone()) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!("[RPC] wallet.exec_sql: Failed casting value to Vec<u8>: {}", e);
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    query = query.bind(val);
-                }
-
-                QueryType::OptionInteger => {
-                    let val: Option<i32> = match serde_json::from_value(pair[1].clone()) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!(
-                                "[RPC] wallet.exec_sql: Failed casting value to Option<i32>: {}",
-                                e
-                            );
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    query = query.bind(val);
-                }
-
-                QueryType::OptionBlob => {
-                    let val: Option<Vec<u8>> = match serde_json::from_value(pair[1].clone()) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!("[RPC] wallet.exec_sql: Failed casting value to Option<Vec<u8>>: {}", e);
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    query = query.bind(val);
-                }
-
-                QueryType::Text => {
-                    let val: String = match serde_json::from_value(pair[1].clone()) {
-                        Ok(v) => v,
-                        Err(e) => {
-                            error!("[RPC] wallet.exec_sql: Failed casting value to String: {}", e);
-                            return JsonError::new(ParseError, None, id).into()
-                        }
-                    };
-
-                    query = query.bind(val);
-                }
-
-                _ => return JsonError::new(InvalidParams, None, id).into(),
-            }
-        }
-
-        // Get a wallet connection
-        let mut conn = match self.wallet.conn.acquire().await {
-            Ok(v) => v,
-            Err(e) => {
-                error!("[RPC] wallet.exec_sql: Failed to acquire wallet connection: {}", e);
-                return JsonError::new(InternalError, None, id).into()
-            }
-        };
-
-        if let Err(e) = query.execute(&mut conn).await {
-            error!("[RPC] wallet.exec_sql: Failed to execute sql query: {}", e);
-            return JsonError::new(InternalError, None, id).into()
-        };
-
-        JsonResponse::new(json!(true), id).into()
-        */
-    }
-}

+ 2 - 2
bin/darkfid2/src/task/miner.rs → bin/darkfid/src/task/miner.rs

@@ -29,7 +29,6 @@ use darkfi::{
     zkas::ZkBinary,
     zkas::ZkBinary,
     Result,
     Result,
 };
 };
-use darkfi_consensus_contract::model::SECRET_KEY_PREFIX;
 use darkfi_money_contract::{
 use darkfi_money_contract::{
     client::pow_reward_v1::PoWRewardCallBuilder, MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
     client::pow_reward_v1::PoWRewardCallBuilder, MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 };
@@ -161,7 +160,8 @@ async fn generate_next_block(
     // We are deriving the next secret key for optimization.
     // We are deriving the next secret key for optimization.
     // Next secret is the poseidon hash of:
     // Next secret is the poseidon hash of:
     //  [prefix, current(previous) secret, signing(block) height].
     //  [prefix, current(previous) secret, signing(block) height].
-    let next_secret = poseidon_hash([SECRET_KEY_PREFIX, secret.inner(), height.into()]);
+    let prefix = pallas::Base::from_raw([4, 0, 0, 0]);
+    let next_secret = poseidon_hash([prefix, secret.inner(), height.into()]);
     *secret = SecretKey::from(next_secret);
     *secret = SecretKey::from(next_secret);
 
 
     // Generate reward transaction
     // Generate reward transaction

+ 0 - 0
bin/darkfid2/src/task/mod.rs → bin/darkfid/src/task/mod.rs


+ 0 - 0
bin/darkfid2/src/task/sync.rs → bin/darkfid/src/task/sync.rs


+ 0 - 0
bin/darkfid2/src/tests/forks.rs → bin/darkfid/src/tests/forks.rs


+ 5 - 8
bin/darkfid2/src/tests/harness.rs → bin/darkfid/src/tests/harness.rs

@@ -36,7 +36,7 @@ use num_bigint::BigUint;
 use url::Url;
 use url::Url;
 
 
 use crate::{
 use crate::{
-    proto::BlockInfoMessage,
+    //  proto::BlockInfoMessage,
     task::sync::sync_task,
     task::sync::sync_task,
     utils::{spawn_consensus_p2p, spawn_sync_p2p},
     utils::{spawn_consensus_p2p, spawn_sync_p2p},
     Darkfid,
     Darkfid,
@@ -65,16 +65,13 @@ impl Harness {
         ex: &Arc<smol::Executor<'static>>,
         ex: &Arc<smol::Executor<'static>>,
     ) -> Result<Self> {
     ) -> Result<Self> {
         // Use test harness to generate genesis transactions
         // Use test harness to generate genesis transactions
-        let mut th =
-            TestHarness::new(&["money".to_string(), "consensus".to_string()], verify_fees).await?;
-        let (genesis_stake_tx, _) = th.genesis_stake(&Holder::Alice, config.alice_initial)?;
+        let mut th = TestHarness::new(&["money".to_string()], verify_fees).await?;
         let (genesis_mint_tx, _) = th.genesis_mint(&Holder::Bob, config.bob_initial)?;
         let (genesis_mint_tx, _) = th.genesis_mint(&Holder::Bob, config.bob_initial)?;
 
 
         // Generate default genesis block
         // Generate default genesis block
         let mut genesis_block = BlockInfo::default();
         let mut genesis_block = BlockInfo::default();
 
 
         // Append genesis transactions and calculate their total
         // Append genesis transactions and calculate their total
-        genesis_block.txs.push(genesis_stake_tx);
         genesis_block.txs.push(genesis_mint_tx);
         genesis_block.txs.push(genesis_mint_tx);
         let genesis_txs_total = genesis_txs_total(&genesis_block.txs).await?;
         let genesis_txs_total = genesis_txs_total(&genesis_block.txs).await?;
         genesis_block.slots[0].total_tokens = genesis_txs_total;
         genesis_block.slots[0].total_tokens = genesis_txs_total;
@@ -171,12 +168,12 @@ impl Harness {
 
 
     pub async fn add_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {
     pub async fn add_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {
         // We simply broadcast the block using Alice's sync P2P
         // We simply broadcast the block using Alice's sync P2P
-        for block in blocks {
-            self.alice.sync_p2p.broadcast(&BlockInfoMessage::from(block)).await;
+        for _block in blocks {
+            //self.alice.sync_p2p.broadcast(&BlockInfoMessage::from(block)).await;
         }
         }
 
 
         // and then add it to her chain
         // and then add it to her chain
-        self.alice.validator.add_blocks(blocks).await?;
+        //self.alice.validator.add_blocks(blocks).await?;
 
 
         Ok(())
         Ok(())
     }
     }

+ 0 - 0
bin/darkfid2/src/tests/mod.rs → bin/darkfid/src/tests/mod.rs


+ 0 - 0
bin/darkfid2/src/utils.rs → bin/darkfid/src/utils.rs


+ 0 - 44
bin/darkfid2/Cargo.toml

@@ -1,44 +0,0 @@
-[package]
-name = "darkfid2"
-version = "0.4.1"
-homepage = "https://dark.fi"
-description = "DarkFi node daemon"
-authors = ["Dyne.org foundation <foundation@dyne.org>"]
-repository = "https://github.com/darkrenaissance/darkfi"
-license = "AGPL-3.0-only"
-edition = "2021"
-
-[dependencies]
-# Darkfi
-darkfi = {path = "../../", features = ["async-daemonize", "bs58"]}
-darkfi_consensus_contract = {path = "../../src/contract/consensus"}
-darkfi_money_contract = {path = "../../src/contract/money"}
-darkfi-contract-test-harness = {path = "../../src/contract/test-harness"}
-darkfi-sdk = {path = "../../src/sdk"}
-darkfi-serial = {path = "../../src/serial"}
-
-# Misc
-blake3 = "1.5.0"
-bs58 = "0.5.0"
-log = "0.4.20"
-num-bigint = "0.4.4"
-rand = "0.8.5"
-sled = "0.34.7"
-toml = "0.8.8"
-
-# JSON-RPC
-async-trait = "0.1.77"
-tinyjson = "2.5.1"
-url = "2.5.0"
-
-# Daemon
-easy-parallel = "3.3.1"
-signal-hook-async-std = "0.2.2"
-signal-hook = "0.3.17"
-simplelog = "0.12.1"
-smol = "1.3.0"
-
-# Argument parsing
-serde = {version = "1.0.195", features = ["derive"]}
-structopt = "0.3.26"
-structopt-toml = "0.5.1"

+ 0 - 42
bin/darkfid2/Makefile

@@ -1,42 +0,0 @@
-.POSIX:
-
-# Install prefix
-PREFIX = $(HOME)/.cargo
-
-# Cargo binary
-CARGO = cargo +nightly
-
-# Compile target
-RUST_TARGET = $(shell rustc -Vv | grep '^host: ' | cut -d' ' -f2)
-# Uncomment when doing musl static builds
-#RUSTFLAGS = -C target-feature=+crt-static -C link-self-contained=yes
-
-SRC = \
-	Cargo.toml \
-	../../Cargo.toml \
-	$(shell find src -type f -name '*.rs') \
-	$(shell find ../../src -type f -name '*.rs') \
-	$(shell find ../../src/contract -type f -name '*.wasm')
-
-BIN = $(shell grep '^name = ' Cargo.toml | cut -d' ' -f3 | tr -d '"')
-
-all: $(BIN)
-
-$(BIN): $(SRC)
-	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) build --target=$(RUST_TARGET) --release --package $@
-	cp -f ../../target/$(RUST_TARGET)/release/$@ $@
-	cp -f ../../target/$(RUST_TARGET)/release/$@ ../../$@
-
-clean:
-	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clean --target=$(RUST_TARGET) --release --package $(BIN)
-	rm -f $(BIN) ../../$(BIN)
-
-install: all
-	mkdir -p $(DESTDIR)$(PREFIX)/bin
-	cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
-	chmod 755 $(DESTDIR)$(PREFIX)/bin/$(BIN)
-
-uninstall:
-	rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN)
-
-.PHONY: all clean install uninstall

+ 0 - 475
bin/darkfid2/darkfid_config.toml

@@ -1,475 +0,0 @@
-## darkfid configuration file
-##
-## Please make sure you go through all the settings so you can configure
-## your daemon properly.
-##
-## The default values are left commented. They can be overridden either by
-## uncommenting, or by using the command-line.
-
-# JSON-RPC listen URL
-rpc_listen = "tcp://127.0.0.1:8340"
-
-# Blockchain network to use
-network = "testnet"
-
-# Localnet blockchain network configuration
-[network_config."localnet"]
-# Path to the blockchain database directory
-database = "~/.local/darkfi/darkfid_blockchain_localnet"
-
-# Finalization threshold, denominated by number of blocks
-threshold = 3
-
-# minerd JSON-RPC endpoint
-minerd_endpoint = "tcp://127.0.0.1:28467"
-
-# PoW block production target, in seconds
-pow_target = 10
-
-# Optional fixed PoW difficulty, used for testing
-pow_fixed_difficulty = 1
-
-# Epoch duration, denominated by number of blocks/slots
-epoch_length = 10
-
-# PoS slot duration, in seconds
-slot_time = 10
-
-# Whitelisted faucet addresses
-faucet_pub = []
-
-# Participate in the consensus protocol
-consensus = true
-
-# Wallet address to receive consensus rewards.
-# This is a dummy one so the miner can start,
-# replace with your own one.
-recipient = "5ZHfYpt4mpJcwBNxfEyxLzeFJUEeoePs5NQ5jVEgHrMf"
-
-# Skip syncing process and start node right away
-skip_sync = true
-
-# Enable PoS testing mode for local testing
-pos_testing_mode = true
-
-## Localnet sync P2P network settings
-[network_config."localnet".sync_net]
-# P2P accept addresses the instance listens on for inbound connections
-inbound = ["tcp+tls://0.0.0.0:8242"]
-
-# P2P external addresses the instance advertises so other peers can
-# reach us and connect to us, as long as inbound addrs are configured.
-#external_addrs = []
-
-# Peer nodes to manually connect to
-#peers = []
-
-# Seed nodes to connect to for peer discovery and/or adversising our
-# own external addresses
-#seeds = []
-
-# Whitelisted network transports for outbound connections
-#allowed_transports = ["tcp+tls"]
-
-# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
-#transport_mixing = true
-
-# Outbound connection slots number, this many connections will be
-# attempted. (This does not include manual connections)
-#outbound_connections = 8
-
-# Inbound connections slots number, this many active inbound connections
-# will be allowed. (This does not include manual or outbound connections)
-#inbound_connections = 0
-
-# Manual connections retry limit, 0 for forever looping
-#manual_attempt_limit = 0
-
-# Outbound connection timeout (in seconds)
-#outbound_connect_timeout = 10
-
-# Exchange versions (handshake) timeout (in seconds)
-#channel_handshake_timeout = 4
-
-# Ping-pong exchange execution interval (in seconds)
-#channel_heartbeat_interval = 10
-
-# Allow localnet hosts
-localnet = true
-
-# Delete a peer from hosts if they've been quarantined N times
-#hosts_quarantine_limit = 50
-
-# Cooling off time for peer discovery when unsuccessful
-#outbound_peer_discovery_cooloff_time = 30
-
-# Time between peer discovery attempts
-#outbound_peer_discovery_attempt_time = 5
-
-## Localnet consensus P2P network settings
-[network_config."localnet".consensus_net]
-# P2P accept addresses the instance listens on for inbound connections
-#inbound = ["tcp+tls://0.0.0.0:8241"]
-
-# P2P external addresses the instance advertises so other peers can
-# reach us and connect to us, as long as inbound addrs are configured.
-#external_addrs = []
-
-# Peer nodes to manually connect to
-#peers = []
-
-# Seed nodes to connect to for peer discovery and/or adversising our
-# own external addresses
-#seeds = []
-
-# Whitelisted network transports for outbound connections
-#allowed_transports = ["tcp+tls"]
-
-# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
-#transport_mixing = true
-
-# Outbound connection slots number, this many connections will be
-# attempted. (This does not include manual connections)
-#outbound_connections = 8
-
-# Manual connections retry limit, 0 for forever looping
-#manual_attempt_limit = 0
-
-# Outbound connection timeout (in seconds)
-#outbound_connect_timeout = 10
-
-# Exchange versions (handshake) timeout (in seconds)
-#channel_handshake_timeout = 4
-
-# Ping-pong exchange execution interval (in seconds)
-#channel_heartbeat_interval = 10
-
-# Allow localnet hosts
-localnet = true
-
-# Delete a peer from hosts if they've been quarantined N times
-#hosts_quarantine_limit = 50
-
-# Cooling off time for peer discovery when unsuccessful
-#outbound_peer_discovery_cooloff_time = 30
-
-# Time between peer discovery attempts
-#outbound_peer_discovery_attempt_time = 5
-
-# Testnet blockchain network configuration
-[network_config."testnet"]
-# Path to the blockchain database directory
-database = "~/.local/darkfi/darkfid_blockchain_testnet"
-
-# Finalization threshold, denominated by number of blocks
-threshold = 6
-
-# minerd JSON-RPC endpoint
-minerd_endpoint = "tcp://127.0.0.1:28467"
-
-# PoW block production target, in seconds
-pow_target = 90
-
-# Epoch duration, denominated by number of blocks/slots
-epoch_length = 10
-
-# PoS slot duration, in seconds
-slot_time = 90
-
-# Whitelisted faucet addresses
-faucet_pub = ["3ce5xa3PjuQGFtTaF7AvMJp7fGxqeGRJx7zj3LCwNCkP"]
-
-# Participate in the consensus protocol
-consensus = false
-
-# Wallet address to receive consensus rewards
-#recipient = "YOUR_WALLET_ADDRESS_HERE"
-
-# Skip syncing process and start node right away
-skip_sync = false
-
-# Enable PoS testing mode for local testing
-pos_testing_mode = false
-
-## Testnet sync P2P network settings
-[network_config."testnet".sync_net]
-# P2P accept addresses the instance listens on for inbound connections
-# You can also use an IPv6 address
-inbound = ["tcp+tls://0.0.0.0:8342"]
-# IPv6 version:
-#inbound = ["tcp+tls://[::]:8342"]
-# Combined:
-#inbound = ["tcp+tls://0.0.0.0:8342", "tcp+tls://[::]:8342"]
-
-# P2P external addresses the instance advertises so other peers can
-# reach us and connect to us, as long as inbound addrs are configured.
-# You can also use an IPv6 address
-#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8342"]
-# IPv6 version:
-#external_addrs = ["tcp+tls://[ipv6 address here]:8342"]
-# Combined:
-#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8342", "tcp+tls://[ipv6 address here]:8342"]
-
-# Peer nodes to manually connect to
-#peers = []
-
-# Seed nodes to connect to for peer discovery and/or adversising our
-# own external addresses
-seeds = ["tcp+tls://lilith0.dark.fi:8342", "tcp+tls://lilith1.dark.fi:8342"]
-
-# Whitelisted network transports for outbound connections
-allowed_transports = ["tcp+tls"]
-
-# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
-#transport_mixing = true
-
-# Outbound connection slots number, this many connections will be
-# attempted. (This does not include manual connections)
-outbound_connections = 8
-
-# Inbound connections slots number, this many active inbound connections
-# will be allowed. (This does not include manual or outbound connections)
-#inbound_connections = 0
-
-# Manual connections retry limit, 0 for forever looping
-#manual_attempt_limit = 0
-
-# Outbound connection timeout (in seconds)
-#outbound_connect_timeout = 10
-
-# Exchange versions (handshake) timeout (in seconds)
-#channel_handshake_timeout = 4
-
-# Ping-pong exchange execution interval (in seconds)
-#channel_heartbeat_interval = 10
-
-# Allow localnet hosts
-localnet = false
-
-# Delete a peer from hosts if they've been quarantined N times
-#hosts_quarantine_limit = 50
-
-# Cooling off time for peer discovery when unsuccessful
-#outbound_peer_discovery_cooloff_time = 30
-
-# Time between peer discovery attempts
-#outbound_peer_discovery_attempt_time = 5
-
-## Testnet consensus P2P network settings
-[network_config."testnet".consensus_net]
-# P2P accept addresses the instance listens on for inbound connections
-# You can also use an IPv6 address
-inbound = ["tcp+tls://0.0.0.0:8341"]
-# IPv6 version:
-#inbound = ["tcp+tls://[::]:8341"]
-# Combined:
-#inbound = ["tcp+tls://0.0.0.0:8341", "tcp+tls://[::]:8341"]
-
-# P2P external addresses the instance advertises so other peers can
-# reach us and connect to us, as long as inbound addrs are configured.
-# You can also use an IPv6 address
-#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8341"]
-# IPv6 version:
-#external_addrs = ["tcp+tls://[ipv6 address here]:8341"]
-# Combined:
-#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8341", "tcp+tls://[ipv6 address here]:8341"]
-
-# Peer nodes to manually connect to
-#peers = []
-
-# Seed nodes to connect to for peer discovery and/or adversising our
-# own external addresses
-seeds = ["tcp+tls://lilith0.dark.fi:8341", "tcp+tls://lilith1.dark.fi:8341"]
-
-# Whitelisted network transports for outbound connections
-allowed_transports = ["tcp+tls"]
-
-# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
-#transport_mixing = true
-
-# Outbound connection slots number, this many connections will be
-# attempted. (This does not include manual connections)
-#outbound_connections = 8
-
-# Manual connections retry limit, 0 for forever looping
-#manual_attempt_limit = 0
-
-# Outbound connection timeout (in seconds)
-#outbound_connect_timeout = 10
-
-# Exchange versions (handshake) timeout (in seconds)
-#channel_handshake_timeout = 4
-
-# Ping-pong exchange execution interval (in seconds)
-#channel_heartbeat_interval = 10
-
-# Allow localnet hosts
-localnet = false
-
-# Delete a peer from hosts if they've been quarantined N times
-#hosts_quarantine_limit = 50
-
-# Cooling off time for peer discovery when unsuccessful
-#outbound_peer_discovery_cooloff_time = 30
-
-# Time between peer discovery attempts
-#outbound_peer_discovery_attempt_time = 5
-
-# Mainnet blockchain network configuration
-[network_config."mainnet"]
-# Path to the blockchain database directory
-database = "~/.local/darkfi/darkfid_blockchain_mainnet"
-
-# Finalization threshold, denominated by number of blocks
-threshold = 11
-
-# minerd JSON-RPC endpoint
-minerd_endpoint = "tcp://127.0.0.1:28467"
-
-# PoW block production target, in seconds
-pow_target = 90
-
-# Epoch duration, denominated by number of blocks/slots
-epoch_length = 10
-
-# PoS slot duration, in seconds
-slot_time = 90
-
-# Whitelisted faucet addresses
-faucet_pub = []
-
-# Participate in the consensus protocol
-consensus = false
-
-# Wallet address to receive consensus rewards
-#recipient = "YOUR_WALLET_ADDRESS_HERE"
-
-# Skip syncing process and start node right away
-skip_sync = false
-
-# Enable PoS testing mode for local testing
-pos_testing_mode = false
-
-## Mainnet sync P2P network settings
-[network_config."mainnet".sync_net]
-# P2P accept addresses the instance listens on for inbound connections
-# You can also use an IPv6 address
-inbound = ["tcp+tls://0.0.0.0:8442"]
-# IPv6 version:
-#inbound = ["tcp+tls://[::]:8442"]
-# Combined:
-#inbound = ["tcp+tls://0.0.0.0:8442", "tcp+tls://[::]:8442"]
-
-# P2P external addresses the instance advertises so other peers can
-# reach us and connect to us, as long as inbound addrs are configured.
-# You can also use an IPv6 address
-#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8442"]
-# IPv6 version:
-#external_addrs = ["tcp+tls://[ipv6 address here]:8442"]
-# Combined:
-#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8442", "tcp+tls://[ipv6 address here]:8442"]
-
-# Peer nodes to manually connect to
-#peers = []
-
-# Seed nodes to connect to for peer discovery and/or adversising our
-# own external addresses
-seeds = ["tcp+tls://lilith0.dark.fi:8442", "tcp+tls://lilith1.dark.fi:8442"]
-
-# Whitelisted network transports for outbound connections
-allowed_transports = ["tcp+tls"]
-
-# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
-#transport_mixing = true
-
-# Outbound connection slots number, this many connections will be
-# attempted. (This does not include manual connections)
-outbound_connections = 8
-
-# Inbound connections slots number, this many active inbound connections
-# will be allowed. (This does not include manual or outbound connections)
-#inbound_connections = 0
-
-# Manual connections retry limit, 0 for forever looping
-#manual_attempt_limit = 0
-
-# Outbound connection timeout (in seconds)
-#outbound_connect_timeout = 10
-
-# Exchange versions (handshake) timeout (in seconds)
-#channel_handshake_timeout = 4
-
-# Ping-pong exchange execution interval (in seconds)
-#channel_heartbeat_interval = 10
-
-# Allow localnet hosts
-localnet = false
-
-# Delete a peer from hosts if they've been quarantined N times
-#hosts_quarantine_limit = 50
-
-# Cooling off time for peer discovery when unsuccessful
-#outbound_peer_discovery_cooloff_time = 30
-
-# Time between peer discovery attempts
-#outbound_peer_discovery_attempt_time = 5
-
-## Mainnet consensus P2P network settings
-[network_config."mainnet".consensus_net]
-# P2P accept addresses the instance listens on for inbound connections
-# You can also use an IPv6 address
-inbound = ["tcp+tls://0.0.0.0:8441"]
-# IPv6 version:
-#inbound = ["tcp+tls://[::]:8441"]
-# Combined:
-#inbound = ["tcp+tls://0.0.0.0:8441", "tcp+tls://[::]:8441"]
-
-# P2P external addresses the instance advertises so other peers can
-# reach us and connect to us, as long as inbound addrs are configured.
-# You can also use an IPv6 address
-#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8441"]
-# IPv6 version:
-#external_addrs = ["tcp+tls://[ipv6 address here]:8441"]
-# Combined:
-#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8441", "tcp+tls://[ipv6 address here]:8441"]
-
-# Peer nodes to manually connect to
-#peers = []
-
-# Seed nodes to connect to for peer discovery and/or adversising our
-# own external addresses
-seeds = ["tcp+tls://lilith0.dark.fi:8441", "tcp+tls://lilith1.dark.fi:8441"]
-
-# Whitelisted network transports for outbound connections
-allowed_transports = ["tcp+tls"]
-
-# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`)
-#transport_mixing = true
-
-# Outbound connection slots number, this many connections will be
-# attempted. (This does not include manual connections)
-#outbound_connections = 8
-
-# Manual connections retry limit, 0 for forever looping
-#manual_attempt_limit = 0
-
-# Outbound connection timeout (in seconds)
-#outbound_connect_timeout = 10
-
-# Exchange versions (handshake) timeout (in seconds)
-#channel_handshake_timeout = 4
-
-# Ping-pong exchange execution interval (in seconds)
-#channel_heartbeat_interval = 10
-
-# Allow localnet hosts
-localnet = false
-
-# Delete a peer from hosts if they've been quarantined N times
-#hosts_quarantine_limit = 50
-
-# Cooling off time for peer discovery when unsuccessful
-#outbound_peer_discovery_cooloff_time = 30
-
-# Time between peer discovery attempts
-#outbound_peer_discovery_attempt_time = 5

+ 0 - 69
bin/darkfid2/src/error.rs

@@ -1,69 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi::rpc::jsonrpc::{ErrorCode::ServerError, JsonError, JsonResult};
-
-/// Custom RPC errors available for darkfid.
-/// Please sort them sensefully.
-pub enum RpcError {
-    // Transaction-related errors
-    TxSimulationFail = -32110,
-    TxBroadcastFail = -32111,
-
-    // State-related errors,
-    NotSynced = -32120,
-    UnknownSlot = -32121,
-
-    // Parsing errors
-    ParseError = -32190,
-
-    // Contract-related errors
-    ContractZkasDbNotFound = -32200,
-
-    // Misc errors
-    PingFailed = -32300,
-}
-
-fn to_tuple(e: RpcError) -> (i32, String) {
-    let msg = match e {
-        // Transaction-related errors
-        RpcError::TxSimulationFail => "Failed simulating transaction state change",
-        RpcError::TxBroadcastFail => "Failed broadcasting transaction",
-        // State-related errors
-        RpcError::NotSynced => "Blockchain is not synced",
-        RpcError::UnknownSlot => "Did not find slot",
-        // Parsing errors
-        RpcError::ParseError => "Parse error",
-        // Contract-related errors
-        RpcError::ContractZkasDbNotFound => "zkas database not found for given contract",
-        // Misc errors
-        RpcError::PingFailed => "Miner daemon ping error",
-    };
-
-    (e as i32, msg.to_string())
-}
-
-pub fn server_error(e: RpcError, id: u16, msg: Option<&str>) -> JsonResult {
-    let (code, default_msg) = to_tuple(e);
-
-    if let Some(message) = msg {
-        return JsonError::new(ServerError(code), Some(message.to_string()), id).into()
-    }
-
-    JsonError::new(ServerError(code), Some(default_msg), id).into()
-}

+ 0 - 419
bin/darkfid2/src/main.rs

@@ -1,419 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::{
-    collections::{HashMap, HashSet},
-    str::FromStr,
-    sync::Arc,
-};
-
-use log::{error, info};
-use smol::{lock::Mutex, stream::StreamExt};
-use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml};
-use url::Url;
-
-use darkfi::{
-    async_daemonize,
-    blockchain::BlockInfo,
-    cli_desc,
-    net::{settings::SettingsOpt, P2pPtr},
-    rpc::{
-        client::RpcClient,
-        jsonrpc::JsonSubscriber,
-        server::{listen_and_serve, RequestHandler},
-    },
-    system::{StoppableTask, StoppableTaskPtr},
-    util::{path::expand_path, time::TimeKeeper},
-    validator::{utils::genesis_txs_total, Validator, ValidatorConfig, ValidatorPtr},
-    Error, Result,
-};
-use darkfi_sdk::crypto::PublicKey;
-use darkfi_serial::deserialize_async;
-
-#[cfg(test)]
-mod tests;
-
-mod error;
-use error::{server_error, RpcError};
-
-/// JSON-RPC requests handler and methods
-mod rpc;
-mod rpc_blockchain;
-mod rpc_tx;
-
-/// Validator async tasks
-mod task;
-use task::{miner_task, sync_task};
-
-/// P2P net protocols
-mod proto;
-
-/// Utility functions
-mod utils;
-use utils::{parse_blockchain_config, spawn_consensus_p2p, spawn_sync_p2p};
-
-const CONFIG_FILE: &str = "darkfid_config.toml";
-const CONFIG_FILE_CONTENTS: &str = include_str!("../darkfid_config.toml");
-/// Note:
-/// If you change these don't forget to remove their corresponding database folder,
-/// since if it already has a genesis block, provided one is ignored.
-const GENESIS_BLOCK_LOCALNET: &str = include_str!("../genesis_block_localnet");
-const GENESIS_BLOCK_TESTNET: &str = include_str!("../genesis_block_testnet");
-const GENESIS_BLOCK_MAINNET: &str = include_str!("../genesis_block_mainnet");
-
-#[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
-#[serde(default)]
-#[structopt(name = "darkfid", about = cli_desc!())]
-struct Args {
-    #[structopt(short, long)]
-    /// Configuration file to use
-    config: Option<String>,
-
-    #[structopt(short, long, default_value = "tcp://127.0.0.1:8340")]
-    /// JSON-RPC listen URL
-    rpc_listen: Url,
-
-    #[structopt(short, long, default_value = "testnet")]
-    /// Blockchain network to use
-    network: String,
-
-    #[structopt(short, long)]
-    /// Set log file to ouput into
-    log: Option<String>,
-
-    #[structopt(short, parse(from_occurrences))]
-    /// Increase verbosity (-vvv supported)
-    verbose: u8,
-}
-
-/// Defines a blockchain network configuration.
-/// Default values correspond to a local network.
-#[derive(Clone, Debug, serde::Deserialize, structopt::StructOpt, structopt_toml::StructOptToml)]
-#[structopt()]
-pub struct BlockchainNetwork {
-    #[structopt(long, default_value = "~/.local/darkfi/darkfid_blockchain_localnet")]
-    /// Path to blockchain database
-    pub database: String,
-
-    #[structopt(long, default_value = "3")]
-    /// Finalization threshold, denominated by number of blocks
-    pub threshold: usize,
-
-    #[structopt(long, default_value = "tcp://127.0.0.1:28467")]
-    /// minerd JSON-RPC endpoint
-    pub minerd_endpoint: Url,
-
-    #[structopt(long, default_value = "10")]
-    /// PoW block production target, in seconds
-    pub pow_target: usize,
-
-    #[structopt(long)]
-    /// Optional fixed PoW difficulty, used for testing
-    pub pow_fixed_difficulty: Option<usize>,
-
-    #[structopt(long, default_value = "10")]
-    /// Epoch duration, denominated by number of blocks/slots
-    pub epoch_length: u64,
-
-    #[structopt(long, default_value = "10")]
-    /// PoS slot duration, in seconds
-    pub slot_time: u64,
-
-    #[structopt(long)]
-    /// Whitelisted faucet public key (repeatable flag)
-    pub faucet_pub: Vec<String>,
-
-    #[structopt(long)]
-    /// Participate in the consensus protocol
-    pub consensus: bool,
-
-    #[structopt(long)]
-    /// Wallet address to receive consensus rewards
-    pub recipient: Option<String>,
-
-    #[structopt(long)]
-    /// Skip syncing process and start node right away
-    pub skip_sync: bool,
-
-    #[structopt(long)]
-    /// Enable PoS testing mode for local testing
-    pub pos_testing_mode: bool,
-
-    /// Syncing network settings
-    #[structopt(flatten)]
-    pub sync_net: SettingsOpt,
-
-    /// Consensus network settings
-    #[structopt(flatten)]
-    pub consensus_net: SettingsOpt,
-}
-
-/// Daemon structure
-pub struct Darkfid {
-    /// Syncing P2P network pointer
-    sync_p2p: P2pPtr,
-    /// Optional consensus P2P network pointer
-    consensus_p2p: Option<P2pPtr>,
-    /// Validator(node) pointer
-    validator: ValidatorPtr,
-    /// A map of various subscribers exporting live info from the blockchain
-    subscribers: HashMap<&'static str, JsonSubscriber>,
-    /// JSON-RPC connection tracker
-    rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
-    /// JSON-RPC client to execute requests to the miner daemon
-    rpc_client: Option<RpcClient>,
-}
-
-impl Darkfid {
-    pub async fn new(
-        sync_p2p: P2pPtr,
-        consensus_p2p: Option<P2pPtr>,
-        validator: ValidatorPtr,
-        subscribers: HashMap<&'static str, JsonSubscriber>,
-        rpc_client: Option<RpcClient>,
-    ) -> Self {
-        Self {
-            sync_p2p,
-            consensus_p2p,
-            validator,
-            subscribers,
-            rpc_connections: Mutex::new(HashSet::new()),
-            rpc_client,
-        }
-    }
-}
-
-async_daemonize!(realmain);
-async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
-    info!(target: "darkfid", "Initializing DarkFi node...");
-
-    // Grab blockchain network configuration
-    let (blockchain_config, genesis_block) = match args.network.as_str() {
-        "localnet" => {
-            (parse_blockchain_config(args.config, "localnet").await?, GENESIS_BLOCK_LOCALNET)
-        }
-        "testnet" => {
-            (parse_blockchain_config(args.config, "testnet").await?, GENESIS_BLOCK_TESTNET)
-        }
-        "mainnet" => {
-            (parse_blockchain_config(args.config, "mainnet").await?, GENESIS_BLOCK_MAINNET)
-        }
-        _ => {
-            error!("Unsupported chain `{}`", args.network);
-            return Err(Error::UnsupportedChain)
-        }
-    };
-
-    if blockchain_config.pos_testing_mode {
-        info!(target: "darkfid", "Node is configured to run in PoS testing mode!");
-    }
-
-    // Parse the genesis block
-    let bytes = bs58::decode(&genesis_block.trim()).into_vec()?;
-    let genesis_block: BlockInfo = deserialize_async(&bytes).await?;
-
-    // Initialize or open sled database
-    let db_path = expand_path(&blockchain_config.database)?;
-    let sled_db = sled::open(&db_path)?;
-
-    // Initialize validator configuration
-    let genesis_txs_total = genesis_txs_total(&genesis_block.txs).await?;
-
-    let time_keeper = TimeKeeper::new(
-        genesis_block.header.timestamp,
-        blockchain_config.epoch_length,
-        blockchain_config.slot_time,
-        0,
-    );
-
-    let pow_fixed_difficulty = if let Some(diff) = blockchain_config.pow_fixed_difficulty {
-        info!(target: "darkfid", "Node is configured to run with fixed PoW difficulty: {}", diff);
-        Some(diff.into())
-    } else {
-        None
-    };
-
-    let config = ValidatorConfig::new(
-        time_keeper,
-        blockchain_config.threshold,
-        blockchain_config.pow_target,
-        pow_fixed_difficulty,
-        genesis_block,
-        genesis_txs_total,
-        vec![],
-        blockchain_config.pos_testing_mode,
-        false, // TODO: Make configurable
-    );
-
-    // Initialize validator
-    let validator = Validator::new(&sled_db, config).await?;
-
-    // Here we initialize various subscribers that can export live blockchain/consensus data.
-    let mut subscribers = HashMap::new();
-    subscribers.insert("blocks", JsonSubscriber::new("blockchain.subscribe_blocks"));
-    subscribers.insert("txs", JsonSubscriber::new("blockchain.subscribe_txs"));
-    if blockchain_config.consensus {
-        subscribers.insert("proposals", JsonSubscriber::new("blockchain.subscribe_proposals"));
-    }
-
-    // Initialize syncing P2P network
-    let sync_p2p =
-        spawn_sync_p2p(&blockchain_config.sync_net.into(), &validator, &subscribers, ex.clone())
-            .await;
-
-    // Initialize consensus P2P network
-    let (consensus_p2p, rpc_client) = if blockchain_config.consensus {
-        let Ok(rpc_client) = RpcClient::new(blockchain_config.minerd_endpoint, ex.clone()).await
-        else {
-            error!(target: "darkfid", "Failed to initialize miner daemon rpc client, check if minerd is running");
-            return Err(Error::RpcClientStopped)
-        };
-        (
-            Some(
-                spawn_consensus_p2p(
-                    &blockchain_config.consensus_net.into(),
-                    &validator,
-                    &subscribers,
-                    ex.clone(),
-                )
-                .await,
-            ),
-            Some(rpc_client),
-        )
-    } else {
-        (None, None)
-    };
-
-    // Initialize node
-    let darkfid = Darkfid::new(
-        sync_p2p.clone(),
-        consensus_p2p.clone(),
-        validator.clone(),
-        subscribers,
-        rpc_client,
-    )
-    .await;
-    let darkfid = Arc::new(darkfid);
-    info!(target: "darkfid", "Node initialized successfully!");
-
-    // Pinging minerd daemon to verify it listens
-    if blockchain_config.consensus {
-        if let Err(e) = darkfid.ping_miner_daemon().await {
-            error!(target: "darkfid", "Failed to ping miner daemon: {}", e);
-            return Err(Error::RpcClientStopped)
-        }
-    }
-
-    // JSON-RPC server
-    info!(target: "darkfid", "Starting JSON-RPC server");
-    // Here we create a task variable so we can manually close the
-    // task later. P2P tasks don't need this since it has its own
-    // stop() function to shut down, also terminating the task we
-    // created for it.
-    let rpc_task = StoppableTask::new();
-    let darkfid_ = darkfid.clone();
-    rpc_task.clone().start(
-        listen_and_serve(args.rpc_listen, darkfid.clone(), None, ex.clone()),
-        |res| async move {
-            match res {
-                Ok(()) | Err(Error::RpcServerStopped) => darkfid_.stop_connections().await,
-                Err(e) => error!(target: "darkfid", "Failed starting sync JSON-RPC server: {}", e),
-            }
-        },
-        Error::RpcServerStopped,
-        ex.clone(),
-    );
-
-    info!(target: "darkfid", "Starting sync P2P network");
-    sync_p2p.clone().start().await?;
-
-    // Consensus protocol
-    if blockchain_config.consensus {
-        info!(target: "darkfid", "Starting consensus P2P network");
-        let consensus_p2p = consensus_p2p.clone().unwrap();
-        consensus_p2p.clone().start().await?;
-    } else {
-        info!(target: "darkfid", "Not starting consensus P2P network");
-    }
-
-    // Sync blockchain
-    if !blockchain_config.skip_sync {
-        sync_task(&darkfid).await?;
-    } else {
-        *darkfid.validator.synced.write().await = true;
-    }
-
-    // Clean node pending transactions
-    darkfid.validator.purge_pending_txs().await?;
-
-    // Consensus protocol
-    let consensus_task = if blockchain_config.consensus {
-        info!(target: "darkfid", "Starting consensus protocol task");
-        // Grab rewards recipient public key(address)
-        if blockchain_config.recipient.is_none() {
-            return Err(Error::ParseFailed("Recipient address missing"))
-        }
-        let recipient = match PublicKey::from_str(&blockchain_config.recipient.unwrap()) {
-            Ok(address) => address,
-            Err(_) => return Err(Error::InvalidAddress),
-        };
-
-        let task = StoppableTask::new();
-        task.clone().start(
-            // Weird hack to prevent lifetimes hell
-            async move { miner_task(&darkfid, &recipient).await },
-            |res| async {
-                match res {
-                    Ok(()) | Err(Error::MinerTaskStopped) => { /* Do nothing */ }
-                    Err(e) => error!(target: "darkfid", "Failed starting miner task: {}", e),
-                }
-            },
-            Error::MinerTaskStopped,
-            ex.clone(),
-        );
-        Some(task)
-    } else {
-        info!(target: "darkfid", "Not participating in consensus");
-        None
-    };
-
-    // Signal handling for graceful termination.
-    let (signals_handler, signals_task) = SignalHandler::new(ex)?;
-    signals_handler.wait_termination(signals_task).await?;
-    info!(target: "darkfid", "Caught termination signal, cleaning up and exiting...");
-
-    info!(target: "darkfid", "Stopping JSON-RPC server...");
-    rpc_task.stop().await;
-
-    info!(target: "darkfid", "Stopping syncing P2P network...");
-    sync_p2p.stop().await;
-
-    if blockchain_config.consensus {
-        info!(target: "darkfid", "Stopping consensus P2P network...");
-        consensus_p2p.unwrap().stop().await;
-
-        info!(target: "darkfid", "Stopping consensus task...");
-        consensus_task.unwrap().stop().await;
-    }
-
-    info!(target: "darkfid", "Flushing sled database...");
-    let flushed_bytes = sled_db.flush_async().await?;
-    info!(target: "darkfid", "Flushed {} bytes", flushed_bytes);
-
-    Ok(())
-}

+ 0 - 292
bin/darkfid2/src/rpc_blockchain.rs

@@ -1,292 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::{collections::HashMap, str::FromStr};
-
-use darkfi_sdk::crypto::ContractId;
-use darkfi_serial::{deserialize_async, serialize_async};
-use log::{debug, error};
-use tinyjson::JsonValue;
-
-use darkfi::{
-    blockchain::contract_store::SMART_CONTRACT_ZKAS_DB_NAME,
-    rpc::jsonrpc::{
-        ErrorCode::{InternalError, InvalidParams, ParseError},
-        JsonError, JsonResponse, JsonResult,
-    },
-    util::encoding::base64,
-};
-
-use crate::{server_error, Darkfid, RpcError};
-
-impl Darkfid {
-    // RPCAPI:
-    // Queries the blockchain database for a block in the given slot.
-    // Returns a readable block upon success.
-    //
-    // **Params:**
-    // * `array[0]`: `u64` slot ID (as string)
-    //
-    // **Returns:**
-    // * [`BlockInfo`](https://darkrenaissance.github.io/darkfi/development/darkfi/consensus/block/struct.BlockInfo.html)
-    //   struct serialized into base64.
-    //
-    // --> {"jsonrpc": "2.0", "method": "blockchain.get_slot", "params": ["0"], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": {...}, "id": 1}
-    pub async fn blockchain_get_slot(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if params.len() != 1 || !params[0].is_string() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        let slot = match params[0].get::<String>().unwrap().parse::<u64>() {
-            Ok(v) => v,
-            Err(_) => return JsonError::new(ParseError, None, id).into(),
-        };
-
-        let blocks = match self.validator.blockchain.get_blocks_by_slot(&[slot]) {
-            Ok(v) => v,
-            Err(e) => {
-                error!(target: "darkfid::rpc::blockchain_get_slot", "Failed fetching block by slot: {}", e);
-                return JsonError::new(InternalError, None, id).into()
-            }
-        };
-
-        if blocks.is_empty() {
-            return server_error(RpcError::UnknownSlot, id, None)
-        }
-
-        let block = base64::encode(&serialize_async(&blocks[0]).await);
-        JsonResponse::new(JsonValue::String(block), id).into()
-    }
-
-    // RPCAPI:
-    // Queries the blockchain database for a given transaction.
-    // Returns a serialized `Transaction` object.
-    //
-    // **Params:**
-    // * `array[0]`: Hex-encoded transaction hash string
-    //
-    // **Returns:**
-    // * Serialized [`Transaction`](https://darkrenaissance.github.io/darkfi/development/darkfi/tx/struct.Transaction.html)
-    //   object encoded with base64
-    //
-    // --> {"jsonrpc": "2.0", "method": "blockchain.get_tx", "params": ["TxHash"], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": "ABCD...", "id": 1}
-    pub async fn blockchain_get_tx(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if params.len() != 1 {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        let tx_hash = params[0].get::<String>().unwrap();
-        let tx_hash = match blake3::Hash::from_hex(tx_hash) {
-            Ok(v) => v,
-            Err(_) => return JsonError::new(ParseError, None, id).into(),
-        };
-
-        let txs = match self.validator.blockchain.transactions.get(&[tx_hash], true) {
-            Ok(txs) => txs,
-            Err(e) => {
-                error!(target: "darkfid::rpc::blockchain_get_tx", "Failed fetching tx by hash: {}", e);
-                return JsonError::new(InternalError, None, id).into()
-            }
-        };
-        // This would be an logic error somewhere
-        assert_eq!(txs.len(), 1);
-        // and strict was used during .get()
-        let tx = txs[0].as_ref().unwrap();
-
-        let tx_enc = base64::encode(&serialize_async(tx).await);
-        JsonResponse::new(JsonValue::String(tx_enc), id).into()
-    }
-
-    // RPCAPI:
-    // Queries the blockchain database to find the last known slot
-    //
-    // **Params:**
-    // * `None`
-    //
-    // **Returns:**
-    // * `u64` ID of the last known slot, as string
-    //
-    // --> {"jsonrpc": "2.0", "method": "blockchain.last_known_slot", "params": [], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": "1234", "id": 1}
-    pub async fn blockchain_last_known_slot(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if !params.is_empty() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        let blockchain = self.validator.blockchain.clone();
-        let Ok(last_slot) = blockchain.last() else {
-            return JsonError::new(InternalError, None, id).into()
-        };
-
-        JsonResponse::new(JsonValue::Number(last_slot.0 as f64), id).into()
-    }
-
-    // RPCAPI:
-    // Initializes a subscription to new incoming blocks.
-    // Once a subscription is established, `darkfid` will send JSON-RPC notifications of
-    // new incoming blocks to the subscriber.
-    //
-    // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_blocks", "params": [], "id": 1}
-    // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_blocks", "params": [`blockinfo`]}
-    pub async fn blockchain_subscribe_blocks(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if !params.is_empty() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        self.subscribers.get("blocks").unwrap().clone().into()
-    }
-
-    // RPCAPI:
-    // Initializes a subscription to new incoming transactions.
-    // Once a subscription is established, `darkfid` will send JSON-RPC notifications of
-    // new incoming transactions to the subscriber.
-    //
-    // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_txs", "params": [], "id": 1}
-    // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_txs", "params": [`tx_hash`]}
-    pub async fn blockchain_subscribe_txs(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if !params.is_empty() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        self.subscribers.get("txs").unwrap().clone().into()
-    }
-
-    // RPCAPI:
-    // Initializes a subscription to new incoming proposals, asuming node participates
-    // in consensus. Once a subscription is established, `darkfid` will send JSON-RPC
-    // notifications of new incoming proposals to the subscriber.
-    //
-    // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_proposals", "params": [], "id": 1}
-    // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_proposals", "params": [`blockinfo`]}
-    pub async fn blockchain_subscribe_proposals(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if !params.is_empty() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        // Since proposals subscriber is only active if we participate to consensus,
-        // we have to check if it actually exists in the subscribers map.
-        let proposals_subscriber = self.subscribers.get("proposals");
-        if proposals_subscriber.is_none() {
-            error!(target: "darkfid::rpc::blockchain_subscribe_proposals", "Proposals subscriber not found");
-            return JsonError::new(InternalError, None, id).into()
-        }
-
-        proposals_subscriber.unwrap().clone().into()
-    }
-
-    // RPCAPI:
-    // Performs a lookup of zkas bincodes for a given contract ID and returns all of
-    // them, including their namespace.
-    //
-    // **Params:**
-    // * `array[0]`: base58-encoded contract ID string
-    //
-    // **Returns:**
-    // * `array[n]`: Pairs of: `zkas_namespace` string, serialized
-    //   [`ZkBinary`](https://darkrenaissance.github.io/darkfi/development/darkfi/zkas/decoder/struct.ZkBinary.html)
-    //   object
-    //
-    // --> {"jsonrpc": "2.0", "method": "blockchain.lookup_zkas", "params": ["6Ef42L1KLZXBoxBuCDto7coi9DA2D2SRtegNqNU4sd74"], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": [["Foo", "ABCD..."], ["Bar", "EFGH..."]], "id": 1}
-    pub async fn blockchain_lookup_zkas(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if params.len() != 1 || !params[0].is_string() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        let contract_id = params[0].get::<String>().unwrap();
-        let contract_id = match ContractId::from_str(contract_id) {
-            Ok(v) => v,
-            Err(e) => {
-                error!(target: "darkfid::rpc::blockchain_lookup_zkas", "Error decoding string to ContractId: {}", e);
-                return JsonError::new(InvalidParams, None, id).into()
-            }
-        };
-
-        let blockchain = self.validator.blockchain.clone();
-
-        let Ok(zkas_db) = blockchain.contracts.lookup(
-            &blockchain.sled_db,
-            &contract_id,
-            SMART_CONTRACT_ZKAS_DB_NAME,
-        ) else {
-            error!(
-                target: "darkfid::rpc::blockchain_lookup_zkas", "Did not find zkas db for ContractId: {}",
-                contract_id
-            );
-            return server_error(RpcError::ContractZkasDbNotFound, id, None)
-        };
-
-        let mut ret = vec![];
-
-        for i in zkas_db.iter() {
-            debug!(target: "darkfid::rpc::blockchain_lookup_zkas", "Iterating over zkas db");
-            let Ok((zkas_ns, zkas_bytes)) = i else {
-                error!(target: "darkfid::rpc::blockchain_lookup_zkas", "Internal sled error iterating db");
-                return JsonError::new(InternalError, None, id).into()
-            };
-
-            let Ok(zkas_ns) = deserialize_async(&zkas_ns).await else {
-                return JsonError::new(InternalError, None, id).into()
-            };
-
-            let zkas_bincode = base64::encode(&zkas_bytes);
-            ret.push(JsonValue::Array(vec![
-                JsonValue::String(zkas_ns),
-                JsonValue::String(zkas_bincode),
-            ]));
-        }
-
-        JsonResponse::new(JsonValue::Array(ret), id).into()
-    }
-
-    // RPCAPI:
-    // Returns the `chain_id` used for merge mining. A 32-byte hash of the genesis block.
-    //
-    // --> {"jsonrpc": "2.0", "method": "merge_mining_get_chain_id", "params": [], "id": 0}
-    // <-- {"jsonrpc": "2.0", "result": {"chain_id": 02f8...7863"}, "id": 0}
-    pub async fn merge_mining_get_chain_id(&self, id: u16, _params: JsonValue) -> JsonResult {
-        let chain_id = match self.validator.blockchain.genesis() {
-            Ok((_, v)) => v,
-            Err(e) => {
-                error!(
-                    target: "darkfid::rpc::merge_mining_get_chain_id",
-                    "[RPC] Error looking up genesis block: {}", e,
-                );
-                return JsonError::new(InternalError, None, id).into()
-            }
-        };
-
-        JsonResponse::new(
-            JsonValue::Object(HashMap::from([(
-                "chain_id".to_string(),
-                chain_id.to_hex().to_string().into(),
-            )])),
-            id,
-        )
-        .into()
-    }
-}

+ 0 - 220
bin/darkfid2/src/rpc_tx.rs

@@ -1,220 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_serial::deserialize_async;
-use log::error;
-use tinyjson::JsonValue;
-
-use darkfi::{
-    rpc::jsonrpc::{
-        ErrorCode::{InternalError, InvalidParams},
-        JsonError, JsonResponse, JsonResult,
-    },
-    tx::Transaction,
-    util::encoding::base64,
-};
-
-use super::Darkfid;
-use crate::{server_error, RpcError};
-
-impl Darkfid {
-    // RPCAPI:
-    // Simulate a network state transition with the given transaction.
-    // Returns `true` if the transaction is valid, otherwise, a corresponding
-    // error.
-    //
-    // --> {"jsonrpc": "2.0", "method": "tx.simulate", "params": ["base64encodedTX"], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
-    pub async fn tx_simulate(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if params.len() != 1 || !params[0].is_string() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        if !*self.validator.synced.read().await {
-            error!(target: "darkfid::rpc::tx_simulate", "Blockchain is not synced");
-            return server_error(RpcError::NotSynced, id, None)
-        }
-
-        // Try to deserialize the transaction
-        let tx_enc = params[0].get::<String>().unwrap().trim();
-        let tx_bytes = match base64::decode(tx_enc) {
-            Some(v) => v,
-            None => {
-                error!(target: "darkfid::rpc::tx_simulate", "Failed decoding base64 transaction");
-                return server_error(RpcError::ParseError, id, None)
-            }
-        };
-
-        let tx: Transaction = match deserialize_async(&tx_bytes).await {
-            Ok(v) => v,
-            Err(e) => {
-                error!(target: "darkfid::rpc::tx_simulate", "Failed deserializing bytes into Transaction: {}", e);
-                return server_error(RpcError::ParseError, id, None)
-            }
-        };
-
-        // Simulate state transition
-        let current_slot = self.validator.consensus.time_keeper.current_slot();
-        let result = self.validator.add_transactions(&[tx], current_slot, false).await;
-        if result.is_err() {
-            error!(
-                target: "darkfid::rpc::tx_simulate", "Failed to validate state transition: {}",
-                result.err().unwrap()
-            );
-            return server_error(RpcError::TxSimulationFail, id, None)
-        };
-
-        JsonResponse::new(JsonValue::Boolean(true), id).into()
-    }
-
-    // RPCAPI:
-    // Broadcast a given transaction to the P2P network.
-    // The function will first simulate the state transition in order to see
-    // if the transaction is actually valid, and in turn it will return an
-    // error if this is the case. Otherwise, a transaction ID will be returned.
-    //
-    // --> {"jsonrpc": "2.0", "method": "tx.broadcast", "params": ["base64encodedTX"], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": "txID...", "id": 1}
-    pub async fn tx_broadcast(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if params.len() != 1 || !params[0].is_string() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        if !*self.validator.synced.read().await {
-            error!(target: "darkfid::rpc::tx_broadcast", "Blockchain is not synced");
-            return server_error(RpcError::NotSynced, id, None)
-        }
-
-        // Try to deserialize the transaction
-        let tx_enc = params[0].get::<String>().unwrap().trim();
-        let tx_bytes = match base64::decode(tx_enc) {
-            Some(v) => v,
-            None => {
-                error!(target: "darkfid::rpc::tx_broadcast", "Failed decoding base64 transaction");
-                return server_error(RpcError::ParseError, id, None)
-            }
-        };
-
-        let tx: Transaction = match deserialize_async(&tx_bytes).await {
-            Ok(v) => v,
-            Err(e) => {
-                error!(target: "darkfid::rpc::tx_broadcast", "Failed deserializing bytes into Transaction: {}", e);
-                return server_error(RpcError::ParseError, id, None)
-            }
-        };
-
-        if self.consensus_p2p.is_some() {
-            // Consensus participants can directly perform
-            // the state transition check and append to their
-            // pending transactions store.
-            if self.validator.append_tx(&tx).await.is_err() {
-                error!(target: "darkfid::rpc::tx_broadcast", "Failed to append transaction to mempool");
-                return server_error(RpcError::TxSimulationFail, id, None)
-            }
-        } else {
-            // We'll perform the state transition check here.
-            let current_slot = self.validator.consensus.time_keeper.current_slot();
-            let result = self.validator.add_transactions(&[tx.clone()], current_slot, false).await;
-            if result.is_err() {
-                error!(
-                    target: "darkfid::rpc::tx_broadcast", "Failed to validate state transition: {}",
-                    result.err().unwrap()
-                );
-                return server_error(RpcError::TxSimulationFail, id, None)
-            };
-        }
-
-        self.sync_p2p.broadcast(&tx).await;
-        if self.sync_p2p.channels().await.is_empty() {
-            error!(target: "darkfid::rpc::tx_broadcast", "Failed broadcasting tx, no connected channels");
-            return server_error(RpcError::TxBroadcastFail, id, None)
-        }
-
-        let tx_hash = tx.hash().unwrap().to_string();
-        JsonResponse::new(JsonValue::String(tx_hash), id).into()
-    }
-
-    // RPCAPI:
-    // Queries the node pending transactions store to retrieve all transactions.
-    // Returns a vector of hex-encoded transaction hashes.
-    //
-    // --> {"jsonrpc": "2.0", "method": "tx.pending", "params": [], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": "[TxHash,...]", "id": 1}
-    pub async fn tx_pending(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if !params.is_empty() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        if !*self.validator.synced.read().await {
-            error!(target: "darkfid::rpc::tx_pending", "Blockchain is not synced");
-            return server_error(RpcError::NotSynced, id, None)
-        }
-
-        let pending_txs = match self.validator.blockchain.get_pending_txs() {
-            Ok(v) => v,
-            Err(e) => {
-                error!(target: "darkfid::rpc::tx_pending", "Failed fetching pending txs: {}", e);
-                return JsonError::new(InternalError, None, id).into()
-            }
-        };
-
-        let pending_txs: Vec<JsonValue> =
-            pending_txs.iter().map(|x| JsonValue::String(x.hash().unwrap().to_string())).collect();
-
-        JsonResponse::new(JsonValue::Array(pending_txs), id).into()
-    }
-
-    // RPCAPI:
-    // Queries the node pending transactions store to remove all transactions.
-    // Returns a vector of hex-encoded transaction hashes.
-    //
-    // --> {"jsonrpc": "2.0", "method": "tx.clean_pending", "params": [], "id": 1}
-    // <-- {"jsonrpc": "2.0", "result": "[TxHash,...]", "id": 1}
-    pub async fn tx_clean_pending(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
-        if !params.is_empty() {
-            return JsonError::new(InvalidParams, None, id).into()
-        }
-
-        if !*self.validator.synced.read().await {
-            error!(target: "darkfid::rpc::tx_clean_pending", "Blockchain is not synced");
-            return server_error(RpcError::NotSynced, id, None)
-        }
-
-        let pending_txs = match self.validator.blockchain.get_pending_txs() {
-            Ok(v) => v,
-            Err(e) => {
-                error!(target: "darkfid::rpc::tx_clean_pending", "Failed fetching pending txs: {}", e);
-                return JsonError::new(InternalError, None, id).into()
-            }
-        };
-
-        if let Err(e) = self.validator.blockchain.remove_pending_txs(&pending_txs) {
-            error!(target: "darkfid::rpc::tx_clean_pending", "Failed fetching pending txs: {}", e);
-            return JsonError::new(InternalError, None, id).into()
-        };
-
-        let pending_txs: Vec<JsonValue> =
-            pending_txs.iter().map(|x| JsonValue::String(x.hash().unwrap().to_string())).collect();
-
-        JsonResponse::new(JsonValue::Array(pending_txs), id).into()
-    }
-}

+ 0 - 1
contrib/docker/riscv.Dockerfile

@@ -67,7 +67,6 @@ ENV TARGET_PRFX="--target=" RUST_TARGET="${RISCV_TARGET}"
 RUN make ${BINS} &&  mkdir compiled-bins && \
 RUN make ${BINS} &&  mkdir compiled-bins && \
     (if [ -e zkas ]; then cp -a zkas compiled-bins/; fi;) && \
     (if [ -e zkas ]; then cp -a zkas compiled-bins/; fi;) && \
     (if [ -e darkfid ]; then cp -a darkfid compiled-bins/; fi;) && \
     (if [ -e darkfid ]; then cp -a darkfid compiled-bins/; fi;) && \
-    (if [ -e darkfid2 ]; then cp -a darkfid2 compiled-bins/; fi;) && \
     (if [ -e faucetd ]; then cp -a faucetd compiled-bins/; fi;) && \
     (if [ -e faucetd ]; then cp -a faucetd compiled-bins/; fi;) && \
     (if [ -e darkirc ]; then cp -a darkirc compiled-bins/; fi;) && \
     (if [ -e darkirc ]; then cp -a darkirc compiled-bins/; fi;) && \
     (if [ -e "genev-cli" ]; then cp -a genev-cli compiled-bins/; fi;) && \
     (if [ -e "genev-cli" ]; then cp -a genev-cli compiled-bins/; fi;) && \

+ 0 - 1
contrib/docker/static.Dockerfile

@@ -48,7 +48,6 @@ RUN sed -e 's,^#RUSTFLAGS ,RUSTFLAGS ,' -i Makefile
 RUN make clean && make ${BINS} &&  mkdir compiled-bins && \
 RUN make clean && make ${BINS} &&  mkdir compiled-bins && \
     (if [ -e zkas ]; then cp -a zkas compiled-bins/; fi;) && \
     (if [ -e zkas ]; then cp -a zkas compiled-bins/; fi;) && \
     (if [ -e darkfid ]; then cp -a darkfid compiled-bins/; fi;) && \
     (if [ -e darkfid ]; then cp -a darkfid compiled-bins/; fi;) && \
-    (if [ -e darkfid2 ]; then cp -a darkfid2 compiled-bins/; fi;) && \
     (if [ -e faucetd ]; then cp -a faucetd compiled-bins/; fi;) && \
     (if [ -e faucetd ]; then cp -a faucetd compiled-bins/; fi;) && \
     (if [ -e darkirc ]; then cp -a darkirc compiled-bins/; fi;) && \
     (if [ -e darkirc ]; then cp -a darkirc compiled-bins/; fi;) && \
     (if [ -e "genev-cli" ]; then cp -a genev-cli compiled-bins/; fi;) && \
     (if [ -e "genev-cli" ]; then cp -a genev-cli compiled-bins/; fi;) && \

+ 0 - 253
src/consensus/block.rs

@@ -1,253 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::fmt;
-
-use darkfi_sdk::{
-    crypto::{MerkleNode, MerkleTree},
-    pasta::pallas,
-};
-use darkfi_serial::{async_trait, serialize, SerialDecodable, SerialEncodable};
-
-use super::{
-    constants::{BLOCK_MAGIC_BYTES, BLOCK_VERSION},
-    LeadInfo,
-};
-use crate::{impl_p2p_message, net::Message, tx::Transaction, util::time::Timestamp};
-
-/// This struct represents a tuple of the form (version, previous, epoch, slot, timestamp, merkle_root).
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct Header {
-    /// Block version
-    pub version: u8,
-    /// Previous block hash
-    pub previous: blake3::Hash,
-    /// Epoch
-    pub epoch: u64,
-    /// Slot UID
-    pub slot: u64,
-    /// Block creation timestamp
-    pub timestamp: Timestamp,
-    /// Root of the transaction hashes merkle tree
-    pub root: MerkleNode,
-}
-
-impl Header {
-    pub fn new(
-        previous: blake3::Hash,
-        epoch: u64,
-        slot: u64,
-        timestamp: Timestamp,
-        root: MerkleNode,
-    ) -> Self {
-        let version = BLOCK_VERSION;
-        Self { version, previous, epoch, slot, timestamp, root }
-    }
-
-    /// Generate the genesis block.
-    pub fn genesis_header(genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Self {
-        let tree = MerkleTree::new(100);
-        let root = tree.root(0).unwrap();
-
-        Self::new(genesis_data, 0, 0, genesis_ts, root)
-    }
-
-    /// Calculate the header hash
-    pub fn headerhash(&self) -> blake3::Hash {
-        blake3::hash(&serialize(self))
-    }
-}
-
-impl Default for Header {
-    fn default() -> Self {
-        Header::new(
-            blake3::hash(b""),
-            0,
-            0,
-            Timestamp::current_time(),
-            MerkleNode::from(pallas::Base::zero()),
-        )
-    }
-}
-
-/// This struct represents a tuple of the form (`magic`, `header`, `counter`, `txs`, `lead_info`).
-/// The header and transactions are stored as hashes, serving as pointers to
-/// the actual data in the sled database.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct Block {
-    /// Block magic bytes
-    pub magic: [u8; 4],
-    /// Block header
-    pub header: blake3::Hash,
-    /// Trasaction hashes
-    pub txs: Vec<blake3::Hash>,
-    /// Lead Info
-    pub lead_info: LeadInfo,
-}
-
-impl_p2p_message!(Block, "block");
-
-impl Block {
-    pub fn new(
-        previous: blake3::Hash,
-        epoch: u64,
-        slot: u64,
-        txs: Vec<blake3::Hash>,
-        root: MerkleNode,
-        lead_info: LeadInfo,
-    ) -> Self {
-        let magic = BLOCK_MAGIC_BYTES;
-        let timestamp = Timestamp::current_time();
-        let header = Header::new(previous, epoch, slot, timestamp, root);
-        let header = header.headerhash();
-        Self { magic, header, txs, lead_info }
-    }
-
-    /// Generate the genesis block.
-    pub fn genesis_block(genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Self {
-        let magic = BLOCK_MAGIC_BYTES;
-        let header = Header::genesis_header(genesis_ts, genesis_data);
-        let header = header.headerhash();
-        let lead_info = LeadInfo::default();
-        Self { magic, header, txs: vec![], lead_info }
-    }
-
-    /// Calculate the block hash
-    pub fn blockhash(&self) -> blake3::Hash {
-        blake3::hash(&serialize(self))
-    }
-}
-
-/// Auxiliary structure used for blockchain syncing.
-#[derive(Debug, SerialEncodable, SerialDecodable)]
-pub struct BlockOrder {
-    /// Slot UID
-    pub slot: u64,
-    /// Block headerhash of that slot
-    pub block: blake3::Hash,
-}
-
-impl_p2p_message!(BlockOrder, "blockorder");
-
-/// Structure representing full block data.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct BlockInfo {
-    /// BlockInfo magic bytes
-    pub magic: [u8; 4],
-    /// Block header data
-    pub header: Header,
-    /// Transactions payload
-    pub txs: Vec<Transaction>,
-    /// Lead Info,
-    pub lead_info: LeadInfo,
-}
-
-impl Default for BlockInfo {
-    fn default() -> Self {
-        let magic = BLOCK_MAGIC_BYTES;
-        Self { magic, header: Header::default(), txs: vec![], lead_info: LeadInfo::default() }
-    }
-}
-
-impl_p2p_message!(BlockInfo, "blockinfo");
-
-impl BlockInfo {
-    pub fn new(header: Header, txs: Vec<Transaction>, lead_info: LeadInfo) -> Self {
-        let magic = BLOCK_MAGIC_BYTES;
-        Self { magic, header, txs, lead_info }
-    }
-
-    /// Calculate the block hash
-    pub fn blockhash(&self) -> blake3::Hash {
-        let block: Block = self.clone().into();
-        block.blockhash()
-    }
-}
-
-impl From<BlockInfo> for Block {
-    fn from(block_info: BlockInfo) -> Self {
-        let txs = block_info.txs.iter().map(|x| blake3::hash(&serialize(x))).collect();
-        Self {
-            magic: block_info.magic,
-            header: block_info.header.headerhash(),
-            txs,
-            lead_info: block_info.lead_info,
-        }
-    }
-}
-
-/// Auxiliary structure used for blockchain syncing
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct BlockResponse {
-    /// Response blocks.
-    pub blocks: Vec<BlockInfo>,
-}
-
-impl_p2p_message!(BlockResponse, "blockresponse");
-
-/// This struct represents a block proposal, used for consensus.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct BlockProposal {
-    /// Block hash
-    pub hash: blake3::Hash,
-    /// Block header hash
-    pub header: blake3::Hash,
-    /// Block data
-    pub block: BlockInfo,
-}
-
-impl BlockProposal {
-    #[allow(clippy::too_many_arguments)]
-    pub fn new(header: Header, txs: Vec<Transaction>, lead_info: LeadInfo) -> Self {
-        let block = BlockInfo::new(header, txs, lead_info);
-        let hash = block.blockhash();
-        let header = block.header.headerhash();
-        Self { hash, header, block }
-    }
-}
-
-impl PartialEq for BlockProposal {
-    fn eq(&self, other: &Self) -> bool {
-        self.hash == other.hash &&
-            self.header == other.header &&
-            self.block.header == other.block.header &&
-            self.block.txs == other.block.txs
-    }
-}
-
-impl fmt::Display for BlockProposal {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        formatter.write_fmt(format_args!(
-            "BlockProposal {{ leader public key: {}, hash: {}, header: {}, epoch: {}, slot: {}, txs: {} }}",
-            self.block.lead_info.public_key,
-            self.hash,
-            self.header,
-            self.block.header.epoch,
-            self.block.header.slot,
-            self.block.txs.len()
-        ))
-    }
-}
-
-impl_p2p_message!(BlockProposal, "proposal");
-
-impl From<BlockProposal> for BlockInfo {
-    fn from(block: BlockProposal) -> BlockInfo {
-        block.block
-    }
-}

+ 0 - 206
src/consensus/clock.rs

@@ -1,206 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use crate::{util::time::Timestamp, Result};
-use log::debug;
-use std::{thread, time::Duration};
-use url::Url;
-
-pub enum Ticks {
-    GENESIS { e: u64, sl: u64 },  //genesis epoch
-    NEWSLOT { e: u64, sl: u64 },  // new slot
-    NEWEPOCH { e: u64, sl: u64 }, // new epoch
-    TOCKS,                        //tocks, or slot is ending
-    IDLE,                         // idle clock state
-    OUTOFSYNC,                    //clock, and blockchain are out of sync
-}
-
-const BB_SL: u64 = u64::MAX - 1; //big bang slot time (need to be negative value)
-const BB_E: u64 = 0; //big bang epoch time.
-
-#[derive(Debug)]
-pub struct Clock {
-    pub sl: u64,       // relative slot index (zero-based) [0-len[
-    pub e: u64,        // epoch index (zero-based) [0-\inf[
-    pub tick_len: u64, // tick length in time (seconds)
-    pub sl_len: u64,   // slot length in ticks
-    pub e_len: u64,    // epoch length in slots
-    pub peers: Vec<Url>,
-    pub genesis_time: Timestamp,
-}
-
-impl Clock {
-    pub fn new(
-        e_len: Option<u64>,
-        sl_len: Option<u64>,
-        tick_len: Option<u64>,
-        peers: Vec<Url>,
-    ) -> Self {
-        let gt: Timestamp = Timestamp::current_time();
-        Self {
-            sl: BB_SL, //necessary for genesis slot
-            e: BB_E,
-            tick_len: tick_len.unwrap_or(22), // 22 seconds
-            sl_len: sl_len.unwrap_or(22),     // ~8 minutes
-            e_len: e_len.unwrap_or(3),        // 24.2 minutes
-            peers,
-            genesis_time: gt,
-        }
-    }
-
-    pub fn get_sl_len(&self) -> u64 {
-        self.sl_len
-    }
-
-    pub fn get_e_len(&self) -> u64 {
-        self.e_len
-    }
-
-    async fn time(&self) -> Result<Timestamp> {
-        //TODO (fix) add more than ntp server to time, and take the avg
-        Ok(Timestamp::current_time())
-    }
-
-    /// returns time since genesis in seconds.
-    async fn time_to_genesis(&self) -> Timestamp {
-        //TODO this value need to be assigned to kickoff time.
-        let genesis_time = self.genesis_time.0;
-        let abs_time = self.time().await.unwrap();
-        Timestamp(abs_time.0 - genesis_time)
-    }
-
-    /// return absolute tick to genesis, and relative tick index in the slot.
-    async fn tick_time(&self) -> (u64, u64, u64) {
-        let time = self.time_to_genesis().await.0;
-        let tick_abs: u64 = time / self.tick_len;
-        let tick_rel: u64 = time % self.tick_len;
-        (time, tick_rel, tick_abs)
-    }
-
-    /// return true if the clock is at the begining (before 2/3 of the slot).
-    async fn ticking(&self) -> bool {
-        let (abs, rel, _) = self.tick_time().await;
-        debug!(target: "consensus::clock", "abs time to genesis ticks: {}, rel ticks: {}", abs, rel);
-        rel < (self.tick_len) * 2 / 3
-    }
-
-    pub async fn sync(&mut self) -> Result<()> {
-        let e = self.epoch_abs().await;
-        let sl = self.slot_relative().await;
-        self.sl = sl;
-        self.e = e;
-        Ok(())
-    }
-
-    /// returns absolute zero based slot index
-    async fn slot_abs(&self) -> u64 {
-        let sl_abs = self.tick_time().await.0 / self.sl_len;
-        debug!(target: "consensus::clock", "[slot_abs] slot len: {} - slot abs: {}", self.sl_len, sl_abs);
-        sl_abs
-    }
-
-    /// returns relative zero based slot index
-    async fn slot_relative(&self) -> u64 {
-        let e_abs = self.slot_abs().await % self.e_len;
-        debug!(target: "consensus::clock", "[slot_relative] slot len: {} - slot relative: {}", self.sl_len, e_abs);
-        e_abs
-    }
-
-    /// returns absolute zero based epoch index.
-    async fn epoch_abs(&self) -> u64 {
-        let res = self.slot_abs().await / self.e_len;
-        debug!(target: "consensus::clock", "[epoch_abs] epoch len: {} - epoch abs: {}", self.e_len, res);
-        res
-    }
-
-    /// return the ticks phase with corresponding phase parameters
-    ///
-    /// the Ticks enum can include epoch index, and relative slot index (zero-based)
-    pub async fn ticks(&mut self) -> Ticks {
-        // also debug the failing function.
-        let e = self.epoch_abs().await;
-        let sl = self.slot_relative().await;
-        if self.ticking().await {
-            debug!(
-                target: "consensus::clock",
-                "e/e`: {}/{} sl/sl`: {}/{}, BB_E/BB_SL: {}/{}",
-                e, self.e, sl, self.sl, BB_E, BB_SL
-            );
-            if e == self.e && e == BB_E && self.sl == BB_SL {
-                self.sl = sl + 1; // 0
-                self.e = e; // 0
-                debug!(target: "consensus::clock", "new genesis");
-                Ticks::GENESIS { e, sl }
-            } else if e == self.e && sl == self.sl + 1 {
-                self.sl = sl;
-                debug!(target: "consensus::clock", "new slot");
-                Ticks::NEWSLOT { e, sl }
-            } else if e == self.e + 1 && sl == 0 {
-                self.e = e;
-                self.sl = sl;
-                debug!(target: "consensus::clock", "new epoch");
-                Ticks::NEWEPOCH { e, sl }
-            } else if e == self.e && sl == self.sl {
-                debug!(target: "consensus::clock", "clock is idle");
-                thread::sleep(Duration::from_millis(100));
-                Ticks::IDLE
-            } else {
-                debug!(target: "consensus::clock", "clock is out of sync");
-                //clock is out of sync
-                Ticks::OUTOFSYNC
-            }
-        } else {
-            debug!(target: "consensus::clock", "tocks");
-            Ticks::TOCKS
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{Clock, Ticks};
-    use futures::executor::block_on;
-    use std::{thread, time::Duration};
-    #[test]
-    fn clock_works() {
-        let clock = Clock::new(Some(9), Some(9), Some(9), vec![]);
-        //block th for 3 secs
-        thread::sleep(Duration::from_millis(1000));
-        let ttg = block_on(clock.time_to_genesis()).0;
-        assert!((1..2).contains(&ttg));
-    }
-
-    fn _clock_ticking() {
-        let clock = Clock::new(Some(9), Some(9), Some(9), vec![]);
-        //block th for 3 secs
-        thread::sleep(Duration::from_millis(1000));
-        assert!(block_on(clock.ticking()));
-        thread::sleep(Duration::from_millis(1000));
-        assert!(block_on(clock.ticking()));
-    }
-
-    fn _clock_ticks() {
-        let mut clock = Clock::new(Some(9), Some(9), Some(9), vec![]);
-        //
-        let tick: Ticks = block_on(clock.ticks());
-        assert!(matches!(tick, Ticks::GENESIS { e: 0, sl: 0 }));
-        thread::sleep(Duration::from_millis(3000));
-        let tock: Ticks = block_on(clock.ticks());
-        assert!(matches!(tock, Ticks::TOCKS));
-    }
-}

+ 0 - 6
src/consensus/consensus_coin.sql

@@ -1,6 +0,0 @@
--- Wallet definitions for consensus lead coins.
-
--- The consensus lead coin we have and can use
-CREATE TABLE IF NOT EXISTS consensus_coin (
-	coin BLOB
-);

+ 0 - 129
src/consensus/constants.rs

@@ -1,129 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use lazy_static::lazy_static;
-
-use crate::{consensus::Float10, util::time::Timestamp};
-
-lazy_static! {
-    /// Genesis hash for the mainnet chain
-    pub static ref MAINNET_GENESIS_HASH_BYTES: blake3::Hash = blake3::hash(b"darkfi_mainnet");
-
-    // NOTE: On initial network bootstrap, genesis timestamp should be equal to boostrap timestamp.
-    // On network restart only change bootstrap timestamp to schedule when nodes become active.
-    /// Genesis timestamp for the mainnet chain
-    pub static ref MAINNET_GENESIS_TIMESTAMP: Timestamp = Timestamp(1650887115);
-
-    /// Bootstrap timestamp for the mainnet chain
-    pub static ref MAINNET_BOOTSTRAP_TIMESTAMP: Timestamp = Timestamp(1650887115);
-
-    /// Total sum of initial staking coins for the mainnet chain
-    pub static ref MAINNET_INITIAL_DISTRIBUTION: u64 = 0;
-
-    /// Genesis hash for the testnet chain
-    pub static ref TESTNET_GENESIS_HASH_BYTES: blake3::Hash = blake3::hash(b"darkfi_testnet");
-
-    /// Genesis timestamp for the testnet chain
-    pub static ref TESTNET_GENESIS_TIMESTAMP: Timestamp = Timestamp(1677531600);
-
-    /// Bootstrap timestamp for the testnet chain
-    pub static ref TESTNET_BOOTSTRAP_TIMESTAMP: Timestamp = Timestamp(1677531600);
-
-    /// Total sum of initial staking coins for the testnet chain
-    pub static ref TESTNET_INITIAL_DISTRIBUTION: u64 = 1000;
-
-    // Commonly used Float10
-    pub static ref FLOAT10_EPSILON: Float10 = Float10::try_from("1").unwrap();
-    pub static ref FLOAT10_NEG_TWO: Float10 = Float10::try_from("-2").unwrap();
-    pub static ref FLOAT10_NEG_ONE: Float10 = Float10::try_from("-1").unwrap();
-    pub static ref FLOAT10_ZERO: Float10 = Float10::try_from("0").unwrap();
-    pub static ref FLOAT10_ONE: Float10 = Float10::try_from("1").unwrap();
-    pub static ref FLOAT10_TWO: Float10 = Float10::try_from("2").unwrap();
-    pub static ref FLOAT10_THREE: Float10 = Float10::try_from("3").unwrap();
-    pub static ref FLOAT10_FIVE: Float10 = Float10::try_from("5").unwrap();
-    pub static ref FLOAT10_NINE: Float10 = Float10::try_from("9").unwrap();
-    pub static ref FLOAT10_TEN: Float10 = Float10::try_from("10").unwrap();
-
-    // Consensus parameters
-    pub static ref KP: Float10 = Float10::try_from("0.18").unwrap();
-    pub static ref KI: Float10 = Float10::try_from("0.02").unwrap();
-    pub static ref KD: Float10 = Float10::try_from("-0.1").unwrap();
-    pub static ref PID_OUT_STEP: Float10  = Float10::try_from("0.1").unwrap();
-    pub static ref MAX_DER: Float10 = Float10::try_from("0.1").unwrap();
-    pub static ref MIN_DER: Float10 = Float10::try_from("-0.1").unwrap();
-    pub static ref MAX_F: Float10 = Float10::try_from("0.99").unwrap();
-    pub static ref MIN_F: Float10 = Float10::try_from("0.01").unwrap();
-
-}
-
-/// Block version number
-pub const BLOCK_VERSION: u8 = 1;
-
-/// Block magic bytes
-pub const BLOCK_MAGIC_BYTES: [u8; 4] = [0x11, 0x6d, 0x75, 0x1f];
-
-/// Block info magic bytes
-pub const BLOCK_INFO_MAGIC_BYTES: [u8; 4] = [0x90, 0x44, 0xf1, 0xf6];
-
-/// Number of slots in one epoch
-pub const EPOCH_LENGTH: usize = 10;
-
-/// Slot time in seconds
-pub const SLOT_TIME: u64 = 90;
-
-/// Finalization sync period duration (should be >=2/3 of slot time)
-pub const FINAL_SYNC_DUR: u64 = 60;
-
-/// Max resync retries duration in epochs
-pub const SYNC_RETRIES_DURATION: u64 = 2;
-
-/// Max resync retries
-pub const SYNC_MAX_RETRIES: u64 = 10;
-
-/// Transactions included in a block cap
-pub const TXS_CAP: usize = 50;
-
-/// Block leader reward
-pub const REWARD: u64 = 1;
-
-/// Leader proofs k for zk proof rows (rows=2^k)
-pub const LEADER_PROOF_K: u32 = 13;
-
-// TODO: Describe these constants
-pub const RADIX_BITS: usize = 76;
-
-pub const P: &str = "28948022309329048855892746252171976963363056481941560715954676764349967630337";
-pub const LOTTERY_HEAD_START: u64 = 1;
-pub const PRF_NULLIFIER_PREFIX: u64 = 0;
-pub const PI_COMMITMENT_X_INDEX: usize = 1;
-pub const PI_COMMITMENT_Y_INDEX: usize = 2;
-pub const PI_COMMITMENT_ROOT: usize = 5;
-pub const PI_NULLIFIER_INDEX: usize = 7;
-pub const PI_MU_Y_INDEX: usize = 8;
-pub const PI_MU_RHO_INDEX: usize = 10;
-pub const PI_SIGMA1_INDEX: usize = 12;
-pub const PI_SIGMA2_INDEX: usize = 13;
-pub const GENESIS_TOTAL_STAKE: u64 = 1;
-
-pub const LEADER_HISTORY_LOG: &str = "/tmp/lead_history.log";
-pub const F_HISTORY_LOG: &str = "/tmp/f_history.log";
-pub const LOTTERY_HISTORY_LOG: &str = "/tmp/lottery_history.log";
-
-// Wallet SQL table constant names. These have to represent the SQL schema.
-pub const CONSENSUS_COIN_TABLE: &str = "consensus_coin";
-pub const CONSENSUS_COIN_COL: &str = "coin";

+ 0 - 87
src/consensus/fees.rs

@@ -1,87 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use crate::zkas::{Opcode, VarType, ZkBinary};
-
-/// Calculate the gas use for verifying a given zkas circuit.
-/// This function assumes that the zkbin was properly decoded.
-pub fn circuit_gas_use(zkbin: &ZkBinary) -> u64 {
-    let mut accumulator: u64 = 0;
-
-    // Constants each with a cost of 10
-    accumulator += 10 * zkbin.constants.len() as u64;
-
-    // Literals each with a cost of 10 (for now there's only 1 type of literal)
-    accumulator += 10 * zkbin.literals.len() as u64;
-
-    // Witnesses have cost by type
-    for witness in &zkbin.witnesses {
-        let cost = match witness {
-            VarType::Dummy => unreachable!(),
-            VarType::EcPoint => 20,
-            VarType::EcFixedPoint => unreachable!(),
-            VarType::EcFixedPointShort => unreachable!(),
-            VarType::EcFixedPointBase => unreachable!(),
-            VarType::EcNiPoint => 20,
-            VarType::Base => 10,
-            VarType::BaseArray => unreachable!(),
-            VarType::Scalar => 20,
-            VarType::ScalarArray => unreachable!(),
-            VarType::MerklePath => 40,
-            VarType::Uint32 => 10,
-            VarType::Uint64 => 10,
-            VarType::Any => 10,
-        };
-
-        accumulator += cost;
-    }
-
-    // Opcodes depending on how heavy they are
-    for opcode in &zkbin.opcodes {
-        let cost = match opcode.0 {
-            Opcode::Noop => unreachable!(),
-            Opcode::EcAdd => 30,
-            Opcode::EcMul => 30,
-            Opcode::EcMulBase => 30,
-            Opcode::EcMulShort => 30,
-            Opcode::EcMulVarBase => 30,
-            Opcode::EcGetX => 5,
-            Opcode::EcGetY => 5,
-            Opcode::PoseidonHash => 20 + 10 * opcode.1.len() as u64,
-            Opcode::MerkleRoot => 50,
-            Opcode::BaseAdd => 15,
-            Opcode::BaseMul => 15,
-            Opcode::BaseSub => 15,
-            Opcode::WitnessBase => 10,
-            Opcode::RangeCheck => 60,
-            Opcode::LessThanStrict => 100,
-            Opcode::LessThanLoose => 100,
-            Opcode::BoolCheck => 20,
-            Opcode::CondSelect => 10,
-            Opcode::ZeroCondSelect => 10,
-            Opcode::ConstrainEqualBase => 10,
-            Opcode::ConstrainEqualPoint => 20,
-            Opcode::ConstrainInstance => 10,
-            Opcode::DebugPrint => 100,
-        };
-
-        accumulator += cost;
-    }
-
-    accumulator
-}

+ 0 - 509
src/consensus/lead_coin.rs

@@ -1,509 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::{
-    crypto::{
-        pedersen::{pedersen_commitment_base, pedersen_commitment_u64},
-        poseidon_hash,
-        util::fp_mod_fv,
-        MerkleNode, MerkleTree, SecretKey,
-    },
-    pasta::{arithmetic::CurveAffine, group::Curve, pallas},
-};
-use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
-use halo2_proofs::{arithmetic::Field, circuit::Value};
-use log::info;
-use rand::rngs::OsRng;
-
-use super::constants::EPOCH_LENGTH;
-use crate::{
-    consensus::{constants, utils::fbig2base, Float10, TransferStx, TxRcpt},
-    zk::{
-        proof::{Proof, ProvingKey},
-        vm::ZkCircuit,
-        vm_heap::Witness,
-    },
-    zkas::ZkBinary,
-    Result,
-};
-
-use std::{
-    fs::File,
-    io::{prelude::*, BufWriter},
-};
-
-pub const MERKLE_DEPTH_LEAD_COIN: usize = 32;
-pub const MERKLE_DEPTH: u8 = 32;
-pub const ZERO: pallas::Base = pallas::Base::zero();
-pub const ONE: pallas::Base = pallas::Base::one();
-pub const PREFIX_EVL: u64 = 2;
-pub const PREFIX_SEED: u64 = 3;
-pub const PREFIX_CM: u64 = 4;
-pub const PREFIX_PK: u64 = 5;
-pub const PREFIX_SN: u64 = 6;
-
-// TODO: Unify item names with the names in the ZK proof (those are more descriptive)
-/// Structure representing the consensus leader coin
-#[derive(Debug, Clone, SerialDecodable, SerialEncodable)]
-pub struct LeadCoin {
-    /// Coin's stake value
-    pub value: u64,
-    /// Coin creation slot.
-    pub slot: u64,
-    /// Coin nonce
-    pub nonce: pallas::Base,
-    /// Commitment for coin1
-    pub coin1_commitment: pallas::Point,
-    /// Merkle root of coin1 commitment
-    pub coin1_commitment_root: MerkleNode,
-    /// Coin commitment position
-    pub coin1_commitment_pos: u32,
-    /// Merkle path to the coin1's commitment
-    pub coin1_commitment_merkle_path: Vec<MerkleNode>,
-    /// coin1 sk
-    pub coin1_sk: pallas::Base,
-    /// Merkle root of the `coin1` secret key
-    pub coin1_sk_root: MerkleNode,
-    /// coin1 sk position in merkle tree
-    pub coin1_sk_pos: u32,
-    /// Merkle path to the secret key of `coin1`
-    pub coin1_sk_merkle_path: Vec<MerkleNode>,
-    /// coin1 commitment blinding factor
-    pub coin1_blind: pallas::Scalar,
-}
-
-impl LeadCoin {
-    /// Create a new `LeadCoin` object using given parameters.
-    #[allow(clippy::too_many_arguments)]
-    pub fn new(
-        // emulation of global random oracle output from previous epoch randomness.
-        //eta: pallas::Base,
-        // Stake value
-        value: u64,
-        // Slot absolute index
-        slot: u64,
-        // coin1 sk
-        coin1_sk: pallas::Base,
-        // Merkle root of the `coin_1` secret key in the Merkle tree of secret keys
-        coin1_sk_root: MerkleNode,
-        // sk pos
-        coin1_sk_pos: usize,
-        // Merkle path to the secret key of `coin_1` in the Merkle tree of secret keys
-        coin1_sk_merkle_path: Vec<MerkleNode>,
-        // coin1 nonce
-        seed: pallas::Base,
-        // Merkle tree of coin commitments
-        coin_commitment_tree: &mut MerkleTree,
-    ) -> Self {
-        // Generate random blinding values for commitments:
-        let coin1_blind = pallas::Scalar::random(&mut OsRng);
-        //let coin2_blind = pallas::Scalar::random(&mut OsRng);
-        // pk
-        let pk = Self::util_pk(coin1_sk_root, slot);
-        let coin1_commitment = Self::commitment(pk, pallas::Base::from(value), seed, coin1_blind);
-        // Hash its coordinates to get a base field element
-        let c1_cm_coords = coin1_commitment.to_affine().coordinates().unwrap();
-        let c1_base_msg = [*c1_cm_coords.x(), *c1_cm_coords.y()];
-        let coin1_commitment_base = poseidon_hash(c1_base_msg);
-        // Append the element to the Merkle tree
-        coin_commitment_tree.append(MerkleNode::from(coin1_commitment_base));
-        let coin1_commitment_pos = coin_commitment_tree.mark().unwrap();
-        let coin1_commitment_root = coin_commitment_tree.root(0).unwrap();
-        let coin1_commitment_merkle_path =
-            coin_commitment_tree.witness(coin1_commitment_pos, 0).unwrap();
-
-        Self {
-            value,
-            slot,
-            nonce: seed,
-            coin1_commitment,
-            coin1_commitment_root,
-            coin1_commitment_pos: u32::try_from(u64::from(coin1_commitment_pos)).unwrap(),
-            coin1_commitment_merkle_path,
-            coin1_sk,
-            coin1_sk_root,
-            coin1_sk_pos: u32::try_from(coin1_sk_pos).unwrap(),
-            coin1_sk_merkle_path,
-            coin1_blind,
-        }
-    }
-
-    pub fn sn(&self) -> pallas::Base {
-        let sn_msg = [pallas::Base::from(PREFIX_SN), self.coin1_sk_root.inner(), self.nonce, ZERO];
-        poseidon_hash(sn_msg)
-    }
-
-    pub fn election_seeds_u64(eta: pallas::Base, slotu64: u64) -> (pallas::Base, pallas::Base) {
-        Self::election_seeds(eta, pallas::Base::from(slotu64))
-    }
-
-    /// Derive election seeds from given parameters
-    pub fn election_seeds(eta: pallas::Base, slot: pallas::Base) -> (pallas::Base, pallas::Base) {
-        info!(target: "consensus::leadcoin", "election_seeds: eta: {:?}, slot: {:?}", eta, slot);
-        let election_seed_nonce = pallas::Base::from(3);
-        let election_seed_lead = pallas::Base::from(22);
-
-        // mu_y
-        let lead_msg = [election_seed_lead, eta, slot];
-        let lead_mu = poseidon_hash(lead_msg);
-
-        // mu_rho
-        let nonce_msg = [election_seed_nonce, eta, slot];
-        let nonce_mu = poseidon_hash(nonce_msg);
-
-        (lead_mu, nonce_mu)
-    }
-
-    /// Create a vector of `pallas::Base` elements from the `LeadCoin` to be
-    /// used as public inputs for the ZK proof.
-    pub fn public_inputs(
-        &self,
-        sigma1: pallas::Base,
-        sigma2: pallas::Base,
-        current_eta: pallas::Base,
-        current_slot: pallas::Base,
-        derived_blind: pallas::Scalar,
-    ) -> Vec<pallas::Base> {
-        // pk
-        let pk = self.pk();
-        // coin 1-2 cm/commitment
-        let c1_cm_coord = self.coin1_commitment.to_affine().coordinates().unwrap();
-        let c2_cm_coord = self.derived_commitment(derived_blind).to_affine().coordinates().unwrap();
-        // lottery seed
-        let seed_msg =
-            [pallas::Base::from(PREFIX_SEED), self.coin1_sk_root.inner(), self.nonce, ZERO];
-        let seed = poseidon_hash(seed_msg);
-        // y
-        let (y_mu, rho_mu) = Self::election_seeds(current_eta, current_slot);
-        let y_msg = [seed, y_mu];
-        let y = poseidon_hash(y_msg);
-        // rho
-        let rho_msg = [seed, rho_mu];
-        let rho = poseidon_hash(rho_msg);
-        let public_inputs = vec![
-            pk,
-            *c1_cm_coord.x(),
-            *c1_cm_coord.y(),
-            *c2_cm_coord.x(),
-            *c2_cm_coord.y(),
-            self.coin1_commitment_root.inner(),
-            self.coin1_sk_root.inner(),
-            self.sn(),
-            y_mu,
-            y,
-            rho_mu,
-            rho,
-            sigma1,
-            sigma2,
-        ];
-        public_inputs
-    }
-
-    fn util_pk(sk_root: MerkleNode, slot: u64) -> pallas::Base {
-        let pk_msg =
-            [pallas::Base::from(PREFIX_PK), sk_root.inner(), pallas::Base::from(slot), ZERO];
-
-        poseidon_hash(pk_msg)
-    }
-    /// calculate coin public key: hash of root coin secret key
-    /// and creation slot.
-    pub fn pk(&self) -> pallas::Base {
-        Self::util_pk(self.coin1_sk_root, self.slot)
-    }
-
-    fn util_derived_rho(sk_root: MerkleNode, nonce: pallas::Base) -> pallas::Base {
-        let rho_msg = [pallas::Base::from(PREFIX_EVL), sk_root.inner(), nonce, ZERO];
-
-        poseidon_hash(rho_msg)
-    }
-    /// calculate derived coin nonce: hash of root coin secret key
-    /// and old nonce
-    pub fn derived_rho(&self) -> pallas::Base {
-        Self::util_derived_rho(self.coin1_sk_root, self.nonce)
-    }
-
-    pub fn headstart() -> pallas::Base {
-        let headstart = constants::MIN_F.clone() * Float10::try_from(constants::P).unwrap();
-        fbig2base(headstart)
-    }
-
-    pub fn is_leader(
-        &self,
-        sigma1: pallas::Base,
-        sigma2: pallas::Base,
-        current_eta: pallas::Base,
-        current_slot: pallas::Base,
-    ) -> bool {
-        let y_seed =
-            [pallas::Base::from(PREFIX_SEED), self.coin1_sk_root.inner(), self.nonce, ZERO];
-        let y_seed_hash = poseidon_hash(y_seed);
-        let (y_mu, _) = Self::election_seeds(current_eta, current_slot);
-        let y_msg = [y_seed_hash, y_mu];
-        let y = poseidon_hash(y_msg);
-
-        let value = pallas::Base::from(self.value);
-
-        let headstart = Self::headstart();
-        let target = sigma1 * value + sigma2 * value * value + headstart;
-
-        let y_t_str = format!("{:?},{:?}\n", y, target);
-        let f =
-            File::options().append(true).create(true).open(constants::LOTTERY_HISTORY_LOG).unwrap();
-
-        {
-            let mut writer = BufWriter::new(f);
-            let _ = writer.write(&y_t_str.into_bytes()).unwrap();
-        }
-        info!(target: "consensus::leadcoin", "is_leader(): y = {:?}", y);
-        info!(target: "consensus::leadcoin", "is_leader(): T = {:?}", target);
-
-        y < target
-    }
-
-    fn commitment(
-        pk: pallas::Base,
-        value: pallas::Base,
-        seed: pallas::Base,
-        blind: pallas::Scalar,
-    ) -> pallas::Point {
-        let commit_msg = [pallas::Base::from(PREFIX_CM), pk, value, seed];
-        // Create commitment to coin
-        let commit_v = poseidon_hash(commit_msg);
-        pedersen_commitment_base(commit_v, blind)
-    }
-    /// calculated derived coin commitment
-    pub fn derived_commitment(&self, blind: pallas::Scalar) -> pallas::Point {
-        let pk = self.pk();
-        let rho = self.derived_rho();
-        Self::commitment(pk, pallas::Base::from(self.value + constants::REWARD), rho, blind)
-    }
-
-    /// the new coin to be minted after the current coin is spent
-    /// in lottery.
-    pub fn derive_coin(
-        &self,
-        coin_commitment_tree: &mut MerkleTree,
-        derived_blind: pallas::Scalar,
-    ) -> LeadCoin {
-        info!(target: "consensus::leadcoin", "derive_coin(): Deriving new coin!");
-        let derived_c1_rho = self.derived_rho();
-        let derived_c1_cm = self.derived_commitment(derived_blind);
-        let derived_c1_cm_coord = derived_c1_cm.to_affine().coordinates().unwrap();
-        let derived_c1_cm_msg = [*derived_c1_cm_coord.x(), *derived_c1_cm_coord.y()];
-        let derived_c1_cm_base = poseidon_hash(derived_c1_cm_msg);
-        coin_commitment_tree.append(MerkleNode::from(derived_c1_cm_base));
-        let leaf_pos = coin_commitment_tree.mark().unwrap();
-        let commitment_root = coin_commitment_tree.root(0).unwrap();
-        let commitment_merkle_path = coin_commitment_tree.witness(leaf_pos, 0).unwrap();
-        LeadCoin {
-            value: self.value + constants::REWARD,
-            slot: self.slot,
-            nonce: derived_c1_rho,
-            coin1_commitment: derived_c1_cm,
-            coin1_commitment_root: commitment_root,
-            coin1_commitment_pos: u32::try_from(u64::from(leaf_pos)).unwrap(),
-            coin1_commitment_merkle_path: commitment_merkle_path,
-            coin1_sk: self.coin1_sk,
-            coin1_sk_root: self.coin1_sk_root,
-            coin1_sk_pos: self.coin1_sk_pos,
-            coin1_sk_merkle_path: self.coin1_sk_merkle_path.clone(),
-            coin1_blind: derived_blind,
-        }
-    }
-
-    /// Try to create a ZK proof of consensus leadership
-    pub fn create_lead_proof(
-        &self,
-        sigma1: pallas::Base,
-        sigma2: pallas::Base,
-        eta: pallas::Base,
-        slot: pallas::Base, //current slot index.
-        pk: &ProvingKey,
-        derived_blind: pallas::Scalar,
-    ) -> (Result<Proof>, Vec<pallas::Base>) {
-        let (y_mu, rho_mu) = Self::election_seeds(eta, slot);
-        let bincode = include_bytes!("../../proof/lead.zk.bin");
-        let zkbin = ZkBinary::decode(bincode).unwrap();
-        let headstart = Self::headstart();
-        let coin1_commitment_merkle_path: [MerkleNode; MERKLE_DEPTH_LEAD_COIN] =
-            self.coin1_commitment_merkle_path.clone().try_into().unwrap();
-        let coin1_sk_merkle_path: [MerkleNode; MERKLE_DEPTH_LEAD_COIN] =
-            self.coin1_sk_merkle_path.clone().try_into().unwrap();
-        let witnesses = vec![
-            Witness::MerklePath(Value::known(coin1_commitment_merkle_path)),
-            Witness::Uint32(Value::known(self.coin1_commitment_pos)),
-            Witness::Uint32(Value::known(self.coin1_sk_pos)),
-            Witness::Base(Value::known(self.coin1_sk)),
-            Witness::Base(Value::known(self.coin1_sk_root.inner())),
-            Witness::MerklePath(Value::known(coin1_sk_merkle_path)),
-            Witness::Base(Value::known(pallas::Base::from(self.slot))),
-            Witness::Base(Value::known(self.nonce)),
-            Witness::Scalar(Value::known(self.coin1_blind)),
-            Witness::Base(Value::known(pallas::Base::from(self.value))),
-            Witness::Scalar(Value::known(derived_blind)),
-            Witness::Base(Value::known(rho_mu)),
-            Witness::Base(Value::known(y_mu)),
-            Witness::Base(Value::known(sigma1)),
-            Witness::Base(Value::known(sigma2)),
-            Witness::Base(Value::known(headstart)),
-        ];
-        let circuit = ZkCircuit::new(witnesses, &zkbin);
-        let public_inputs = self.public_inputs(sigma1, sigma2, eta, slot, derived_blind);
-        (Ok(Proof::create(pk, &[circuit], &public_inputs, &mut OsRng).unwrap()), public_inputs)
-    }
-
-    #[allow(clippy::too_many_arguments)]
-    pub fn create_xfer_proof(
-        &self,
-        pk: &ProvingKey,
-        change_coin: TxRcpt,
-        change_pk: pallas::Base, //change coin public key
-        transfered_coin: TxRcpt,
-        transfered_pk: pallas::Base, // recipient coin's public key
-        sigma1: pallas::Base,
-        sigma2: pallas::Base,
-        current_eta: pallas::Base,
-        current_slot: pallas::Base,
-        derived_blind: pallas::Scalar,
-    ) -> Result<TransferStx> {
-        assert!(change_coin.value + transfered_coin.value == self.value && self.value > 0);
-        let bincode = include_bytes!("../../proof/tx.zk.bin");
-        let zkbin = ZkBinary::decode(bincode)?;
-        let retval = pallas::Base::from(change_coin.value);
-        let xferval = pallas::Base::from(transfered_coin.value);
-        let pos: u32 = self.coin1_commitment_pos;
-        let value = pallas::Base::from(self.value);
-        let coin1_sk_merkle_path: [MerkleNode; MERKLE_DEPTH_LEAD_COIN] =
-            self.coin1_sk_merkle_path.clone().try_into().unwrap();
-        let coin1_commitment_merkle_path: [MerkleNode; MERKLE_DEPTH_LEAD_COIN] =
-            self.coin1_commitment_merkle_path.clone().try_into().unwrap();
-        let witnesses = vec![
-            // coin (1) burned coin
-            Witness::Base(Value::known(self.coin1_commitment_root.inner())),
-            Witness::Base(Value::known(self.coin1_sk_root.inner())),
-            Witness::Base(Value::known(self.coin1_sk)),
-            Witness::MerklePath(Value::known(coin1_sk_merkle_path)),
-            Witness::Uint32(Value::known(self.coin1_sk_pos)),
-            Witness::Base(Value::known(self.nonce)),
-            Witness::Scalar(Value::known(self.coin1_blind)),
-            Witness::Base(Value::known(value)),
-            Witness::MerklePath(Value::known(coin1_commitment_merkle_path)),
-            Witness::Uint32(Value::known(pos)),
-            Witness::Base(Value::known(self.sn())),
-            // coin (3)
-            Witness::Base(Value::known(change_pk)),
-            Witness::Base(Value::known(change_coin.rho)),
-            Witness::Scalar(Value::known(change_coin.opening)),
-            Witness::Base(Value::known(retval)),
-            // coin (4)
-            Witness::Base(Value::known(transfered_pk)),
-            Witness::Base(Value::known(transfered_coin.rho)),
-            Witness::Scalar(Value::known(transfered_coin.opening)),
-            Witness::Base(Value::known(xferval)),
-        ];
-        let circuit = ZkCircuit::new(witnesses, &zkbin);
-        let proof = Proof::create(
-            pk,
-            &[circuit],
-            &self.public_inputs(sigma1, sigma2, current_eta, current_slot, derived_blind),
-            &mut OsRng,
-        )?;
-        let cm3_msg_in = [
-            pallas::Base::from(PREFIX_CM),
-            change_pk,
-            pallas::Base::from(change_coin.value),
-            change_coin.rho,
-        ];
-        let cm3_msg = poseidon_hash(cm3_msg_in);
-        let cm3 = pedersen_commitment_base(cm3_msg, change_coin.opening);
-        let cm4_msg_in = [
-            pallas::Base::from(PREFIX_CM),
-            transfered_pk,
-            pallas::Base::from(transfered_coin.value),
-            transfered_coin.rho,
-        ];
-        let cm4_msg = poseidon_hash(cm4_msg_in);
-        let cm4 = pedersen_commitment_base(cm4_msg, transfered_coin.opening);
-        let tx = TransferStx {
-            coin_commitment: self.coin1_commitment,
-            coin_pk: self.pk(),
-            coin_root_sk: self.coin1_sk_root,
-            change_coin_commitment: cm3,
-            transfered_coin_commitment: cm4,
-            nullifier: self.sn(),
-            slot: pallas::Base::from(self.slot),
-            root: self.coin1_commitment_root,
-            proof,
-        };
-        Ok(tx)
-    }
-}
-
-/// This struct holds the secrets for creating LeadCoins during one epoch.
-pub struct LeadCoinSecrets {
-    pub secret_keys: Vec<SecretKey>,
-    pub merkle_roots: Vec<MerkleNode>,
-    pub merkle_paths: Vec<Vec<MerkleNode>>,
-}
-
-impl LeadCoinSecrets {
-    /// Generate epoch coins secret keys.
-    /// First clot coin secret key is sampled at random, while the secret keys of the
-    /// remaining slots derive from the previous slot secret.
-    /// Clarification:
-    /// ```plaintext
-    /// sk[0] -> random,
-    /// sk[1] -> derive_function(sk[0]),
-    /// ...
-    /// sk[n] -> derive_function(sk[n-1]),
-    /// ```
-    pub fn generate() -> Self {
-        let mut tree = MerkleTree::new(EPOCH_LENGTH);
-        let mut sks = Vec::with_capacity(EPOCH_LENGTH);
-        let mut root_sks = Vec::with_capacity(EPOCH_LENGTH);
-        let mut path_sks = Vec::with_capacity(EPOCH_LENGTH);
-
-        let mut prev_sk = SecretKey::from(pallas::Base::one());
-
-        for i in 0..EPOCH_LENGTH {
-            let secret = if i == 0 {
-                pedersen_commitment_u64(1, pallas::Scalar::random(&mut OsRng))
-            } else {
-                pedersen_commitment_u64(1, fp_mod_fv(prev_sk.inner()))
-            };
-
-            let secret_coords = secret.to_affine().coordinates().unwrap();
-            let secret_msg = [*secret_coords.x(), *secret_coords.y()];
-            let secret_key = SecretKey::from(poseidon_hash(secret_msg));
-
-            sks.push(secret_key);
-            prev_sk = secret_key;
-
-            let node = MerkleNode::from(secret_key.inner());
-            tree.append(node);
-            let leaf_pos = tree.mark().unwrap();
-            let root = tree.root(0).unwrap();
-            let path = tree.witness(leaf_pos, 0).unwrap();
-
-            root_sks.push(root);
-            path_sks.push(path);
-        }
-
-        Self { secret_keys: sks, merkle_roots: root_sks, merkle_paths: path_sks }
-    }
-}

+ 0 - 111
src/consensus/lead_info.rs

@@ -1,111 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::{
-    crypto::{schnorr::Signature, Keypair, PublicKey},
-    pasta::pallas,
-};
-use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
-use log::error;
-
-use crate::{
-    zk::proof::{Proof, VerifyingKey},
-    Result,
-};
-
-// TODO: Replace 'Lead' terms with 'Producer' to make it more clear that
-// we refer to block producer.
-/// This struct represents [`Block`](super::Block) leader information used by the consensus protocol.
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct LeadInfo {
-    /// Block producer signature
-    pub signature: Signature,
-    /// Block producer public_key
-    pub public_key: PublicKey, // TODO: remove this(to be derived by proof)
-    /// Block producer slot competing coins public inputs
-    pub public_inputs: Vec<pallas::Base>,
-    /// Leader coin creation slot
-    pub coin_slot: u64,
-    /// Leader coin creation eta
-    pub coin_eta: pallas::Base,
-    /// Leader NIZK proof
-    pub proof: LeadProof,
-    /// Block producer leaders count
-    pub leaders: u64,
-}
-
-impl Default for LeadInfo {
-    /// Default LeadInfo used in genesis block generation
-    fn default() -> Self {
-        let keypair = Keypair::default();
-        let signature = Signature::dummy();
-        let public_inputs = vec![];
-        let coin_slot = 0;
-        let coin_eta = pallas::Base::zero();
-        let proof = LeadProof::default();
-        let leaders = 0;
-        Self {
-            signature,
-            public_key: keypair.public,
-            public_inputs,
-            coin_slot,
-            coin_eta,
-            proof,
-            leaders,
-        }
-    }
-}
-
-impl LeadInfo {
-    #[allow(clippy::too_many_arguments)]
-    pub fn new(
-        signature: Signature,
-        public_key: PublicKey,
-        public_inputs: Vec<pallas::Base>,
-        coin_slot: u64,
-        coin_eta: pallas::Base,
-        proof: LeadProof,
-        leaders: u64,
-    ) -> Self {
-        Self { signature, public_key, public_inputs, coin_slot, coin_eta, proof, leaders }
-    }
-}
-
-/// Wrapper over the Proof, for future additions.
-#[derive(Default, Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct LeadProof {
-    /// Leadership proof
-    pub proof: Proof,
-}
-
-impl LeadProof {
-    pub fn verify(&self, vk: &VerifyingKey, public_inputs: &[pallas::Base]) -> Result<()> {
-        if let Err(e) = self.proof.verify(vk, public_inputs) {
-            error!(target: "consensus::lead_info", "Verification of consensus lead proof failed: {}", e);
-            return Err(e.into())
-        }
-
-        Ok(())
-    }
-}
-
-impl From<Proof> for LeadProof {
-    fn from(proof: Proof) -> Self {
-        Self { proof }
-    }
-}

+ 0 - 78
src/consensus/mod.rs

@@ -1,78 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-/// Block definition
-pub mod block;
-pub use block::{Block, BlockInfo, BlockProposal, Header};
-
-/// Constants
-pub mod constants;
-pub use constants::{
-    TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP,
-    TESTNET_INITIAL_DISTRIBUTION,
-};
-
-/// Consensus block leader information
-pub mod lead_info;
-pub use lead_info::{LeadInfo, LeadProof};
-
-/// Consensus state
-pub mod state;
-
-/// Consensus validator state
-pub mod validator;
-pub use validator::{ValidatorState, ValidatorStatePtr};
-
-/// Fee calculations
-pub mod fees;
-
-/// P2P net protocols
-pub mod proto;
-
-/// async tasks to utilize the protocols
-pub mod task;
-
-/// Lamport clock
-pub mod clock;
-pub use clock::{Clock, Ticks};
-
-/// Consensus participation coin functions and definitions
-pub mod lead_coin;
-pub use lead_coin::LeadCoin;
-
-/// Utility types
-pub mod types;
-pub use types::Float10;
-
-/// Utility functions
-pub mod utils;
-
-/// Wallet functions
-pub mod wallet;
-
-/// transfered tx proof with public inputs.
-pub mod stx;
-pub use stx::TransferStx;
-
-/// encrypted receipient coin info
-pub mod rcpt;
-pub use rcpt::{EncryptedTxRcpt, TxRcpt};
-
-/// transfer transaction
-pub mod tx;
-pub use tx::Tx;

+ 0 - 33
src/consensus/proto/mod.rs

@@ -1,33 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-/// Block proposal protocol
-mod protocol_proposal;
-pub use protocol_proposal::ProtocolProposal;
-
-/// Transaction broadcast protocol
-mod protocol_tx;
-pub use protocol_tx::ProtocolTx;
-
-/// Validator + Replicator blockchain sync protocol
-mod protocol_sync;
-pub use protocol_sync::ProtocolSync;
-
-/// Validator consensus sync protocol
-mod protocol_sync_consensus;
-pub use protocol_sync_consensus::ProtocolSyncConsensus;

+ 0 - 134
src/consensus/proto/protocol_proposal.rs

@@ -1,134 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::sync::Arc;
-
-use async_trait::async_trait;
-use log::{debug, error, trace};
-use smol::Executor;
-use url::Url;
-
-use crate::{
-    consensus::{BlockProposal, ValidatorStatePtr},
-    net::{
-        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
-        ProtocolJobsManager, ProtocolJobsManagerPtr,
-    },
-    Result,
-};
-
-pub struct ProtocolProposal {
-    proposal_sub: MessageSubscription<BlockProposal>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-    p2p: P2pPtr,
-    channel_address: Url,
-}
-
-impl ProtocolProposal {
-    pub async fn init(
-        channel: ChannelPtr,
-        state: ValidatorStatePtr,
-        p2p: P2pPtr,
-    ) -> Result<ProtocolBasePtr> {
-        debug!(target: "consensus::protocol_proposal::init()", "Adding ProtocolProposal to the protocol registry");
-        let msg_subsystem = channel.message_subsystem();
-        msg_subsystem.add_dispatch::<BlockProposal>().await;
-
-        let proposal_sub = channel.subscribe_msg::<BlockProposal>().await?;
-
-        Ok(Arc::new(Self {
-            proposal_sub,
-            jobsman: ProtocolJobsManager::new("ProposalProtocol", channel.clone()),
-            state,
-            p2p,
-            channel_address: channel.address().clone(),
-        }))
-    }
-
-    async fn handle_receive_proposal(self: Arc<Self>) -> Result<()> {
-        debug!(target: "consensus::protocol_proposal::handle_receive_proposal()", "START");
-        let exclude_list = vec![self.channel_address.clone()];
-        loop {
-            let proposal = match self.proposal_sub.receive().await {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_proposal::handle_receive_proposal()",
-                        "recv fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-
-            debug!(
-                target: "consensus::protocol_proposal::handle_receive_proposal()",
-                "recv: {}", proposal);
-            trace!(
-                target: "consensus::protocol_proposal::handle_receive_proposal()",
-                "Full proposal: {:?}",
-                proposal
-            );
-
-            let proposal_copy = (*proposal).clone();
-
-            // Verify we have the proposal already
-            let mut lock = self.state.write().await;
-            if lock.consensus.proposal_exists(&proposal_copy.hash) {
-                debug!(
-                    target: "consensus::protocol_proposal::handle_receive_proposal()",
-                    "Proposal already received."
-                );
-                continue
-            }
-
-            match lock.receive_proposal(&proposal_copy, None).await {
-                Ok(broadcast) => {
-                    if broadcast {
-                        // Broadcast proposal to rest of nodes
-                        self.p2p.broadcast_with_exclude(&proposal_copy, &exclude_list).await;
-                    }
-                }
-                Err(e) => {
-                    error!(
-                        target: "consensus::protocol_proposal::handle_receive_proposal()",
-                        "receive_proposal error: {}",
-                        e
-                    );
-                    continue
-                }
-            }
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolProposal {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(target: "consensus::protocol_proposal::start()", "START");
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman.clone().spawn(self.clone().handle_receive_proposal(), executor.clone()).await;
-        debug!(target: "consensus::protocol_proposal::start()", "END");
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolProposal"
-    }
-}

+ 0 - 374
src/consensus/proto/protocol_sync.rs

@@ -1,374 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::sync::Arc;
-
-use async_trait::async_trait;
-use log::{debug, error, info};
-use smol::Executor;
-
-use darkfi_sdk::blockchain::Slot;
-
-use crate::{
-    consensus::{
-        block::{BlockInfo, BlockOrder, BlockResponse},
-        state::{SlotRequest, SlotResponse},
-        ValidatorStatePtr,
-    },
-    net::{
-        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
-        ProtocolJobsManager, ProtocolJobsManagerPtr,
-    },
-    Result,
-};
-
-// Constant defining how many blocks we send during syncing.
-const BATCH: u64 = 10;
-
-pub struct ProtocolSync {
-    channel: ChannelPtr,
-    request_sub: MessageSubscription<BlockOrder>,
-    slot_request_sub: MessageSubscription<SlotRequest>,
-    block_sub: MessageSubscription<BlockInfo>,
-    slots_sub: MessageSubscription<Slot>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-    p2p: P2pPtr,
-    consensus_mode: bool,
-}
-
-impl ProtocolSync {
-    pub async fn init(
-        channel: ChannelPtr,
-        state: ValidatorStatePtr,
-        p2p: P2pPtr,
-        consensus_mode: bool,
-    ) -> Result<ProtocolBasePtr> {
-        let msg_subsystem = channel.message_subsystem();
-        msg_subsystem.add_dispatch::<BlockOrder>().await;
-        msg_subsystem.add_dispatch::<SlotRequest>().await;
-        msg_subsystem.add_dispatch::<BlockInfo>().await;
-        msg_subsystem.add_dispatch::<Slot>().await;
-
-        let request_sub = channel.subscribe_msg::<BlockOrder>().await?;
-        let slot_request_sub = channel.subscribe_msg::<SlotRequest>().await?;
-        let block_sub = channel.subscribe_msg::<BlockInfo>().await?;
-        let slots_sub = channel.subscribe_msg::<Slot>().await?;
-
-        Ok(Arc::new(Self {
-            channel: channel.clone(),
-            request_sub,
-            slot_request_sub,
-            block_sub,
-            slots_sub,
-            jobsman: ProtocolJobsManager::new("SyncProtocol", channel),
-            state,
-            p2p,
-            consensus_mode,
-        }))
-    }
-
-    async fn handle_receive_request(self: Arc<Self>) -> Result<()> {
-        debug!(
-            target: "consensus::protocol_sync::handle_receive_request()",
-            "START"
-        );
-        loop {
-            let order = match self.request_sub.receive().await {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_sync::handle_receive_request()",
-                        "recv fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-
-            debug!(
-                target: "consensus::protocol_sync::handle_receive_request()",
-                "received {:?}",
-                order
-            );
-
-            // Extra validations can be added here
-            /*
-            let key = order.slot;
-            let blocks = match self.state.read().await.blockchain.get_blocks_after(key, BATCH) {
-                Ok(v) => v,
-                Err(e) => {
-                    error!(
-                        target: "consensus::protocol_sync::handle_receive_request()",
-                        "get_blocks_after fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-            debug!(
-                target: "consensus::protocol_sync::handle_receive_request()",
-                "Found {} blocks",
-                blocks.len()
-            );
-            */
-            let blocks = vec![BlockInfo::default()];
-
-            let response = BlockResponse { blocks };
-            if let Err(e) = self.channel.send(&response).await {
-                error!(
-                    target: "consensus::protocol_sync::handle_receive_request()",
-                    "channel send fail: {}",
-                    e
-                )
-            };
-        }
-    }
-
-    async fn handle_receive_block(self: Arc<Self>) -> Result<()> {
-        debug!(target: "consensus::protocol_sync::handle_receive_block()", "START");
-        let _exclude_list = [self.channel.address()];
-        loop {
-            let info = match self.block_sub.receive().await {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_sync::handle_receive_block()",
-                        "recv fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-
-            // Check if node has finished syncing its blockchain
-            if !self.state.read().await.synced {
-                debug!(
-                    target: "consensus::protocol_sync::handle_receive_block()",
-                    "Node still syncing blockchain, skipping..."
-                );
-                continue
-            }
-
-            // Check if node started participating in consensus.
-            // Consensus-mode enabled nodes have already performed these steps,
-            // during proposal finalization. They still listen to this sub,
-            // in case they go out of sync and become a none-consensus node.
-            if self.consensus_mode {
-                let lock = self.state.read().await;
-                let current = lock.consensus.time_keeper.current_slot();
-                let participating = lock.consensus.participating;
-                if let Some(slot) = participating {
-                    if current >= slot {
-                        debug!(
-                            target: "consensus::protocol_sync::handle_receive_block()",
-                            "node runs in consensus mode, skipping..."
-                        );
-                        continue
-                    }
-                }
-            }
-
-            info!(
-                target: "consensus::protocol_sync::handle_receive_block()",
-                "Received block: {}",
-                info.blockhash()
-            );
-
-            debug!(
-                target: "consensus::protocol_sync::handle_receive_block()",
-                "Processing received block"
-            );
-            /*
-            let info_copy = (*info).clone();
-            match self.state.write().await.receive_finalized_block(info_copy.clone()).await {
-                Ok(v) => {
-                    if v {
-                        debug!(
-                            target: "consensus::protocol_sync::handle_receive_block()",
-                            "block processed successfully, broadcasting..."
-                        );
-                        self.p2p.broadcast_with_exclude(&info_copy, &exclude_list).await;
-                    }
-                }
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_sync::handle_receive_block()",
-                        "error processing finalized block: {}",
-                        e
-                    );
-                }
-            };
-            */
-        }
-    }
-
-    async fn handle_receive_slot_request(self: Arc<Self>) -> Result<()> {
-        debug!(
-            target: "consensus::protocol_sync::handle_receive_slot_request()",
-            "START"
-        );
-        loop {
-            let request = match self.slot_request_sub.receive().await {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_sync::handle_receive_slot_request()",
-                        "recv fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-
-            debug!(
-                target: "consensus::protocol_sync::handle_receive_slot_request()",
-                "received {:?}",
-                request
-            );
-
-            // Extra validations can be added here
-            let key = request.slot;
-            let slots = match self.state.read().await.blockchain.get_slots_after(key, BATCH) {
-                Ok(v) => v,
-                Err(e) => {
-                    error!(
-                        target: "consensus::protocol_sync::handle_receive_slot_request()",
-                        "get_slots_after fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-            debug!(
-                target: "consensus::protocol_sync::handle_receive_slot_request()",
-                "Found {} slots",
-                slots.len()
-            );
-
-            let response = SlotResponse { slots };
-            if let Err(e) = self.channel.send(&response).await {
-                error!(
-                    target: "consensus::protocol_sync::handle_receive_slot_request()",
-                    "channel send fail: {}",
-                    e
-                )
-            };
-        }
-    }
-
-    async fn handle_receive_slot(self: Arc<Self>) -> Result<()> {
-        debug!(
-            target: "consensus::protocol_sync::handle_receive_slot()",
-            "START"
-        );
-        let exclude_list = vec![self.channel.address().clone()];
-        loop {
-            let slot = match self.slots_sub.receive().await {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_sync::handle_receive_slot()",
-                        "recv fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-
-            // Check if node has finished syncing its blockchain
-            if !self.state.read().await.synced {
-                debug!(
-                    target: "consensus::protocol_sync::handle_receive_slot()",
-                    "Node still syncing blockchain, skipping..."
-                );
-                continue
-            }
-
-            // Check if node started participating in consensus.
-            // Consensus-mode enabled nodes have already performed these steps,
-            // during proposal finalization. They still listen to this sub,
-            // in case they go out of sync and become a none-consensus node.
-            if self.consensus_mode {
-                let lock = self.state.read().await;
-                let current = lock.consensus.time_keeper.current_slot();
-                let participating = lock.consensus.participating;
-                if let Some(slot) = participating {
-                    if current >= slot {
-                        debug!(
-                            target: "consensus::protocol_sync::handle_receive_slot()",
-                            "node runs in consensus mode, skipping..."
-                        );
-                        continue
-                    }
-                }
-            }
-
-            info!(
-                target: "consensus::protocol_sync::handle_receive_slot()",
-                "Received slot: {}",
-                slot.id
-            );
-
-            debug!(
-                target: "consensus::protocol_sync::handle_receive_slot()",
-                "Processing received slot"
-            );
-            let slot_copy = (*slot).clone();
-            match self.state.write().await.receive_finalized_slots(slot_copy.clone()).await {
-                Ok(v) => {
-                    if v {
-                        debug!(
-                            target: "consensus::protocol_sync::handle_receive_slot()",
-                            "slot processed successfully, broadcasting..."
-                        );
-                        self.p2p.broadcast_with_exclude(&slot_copy, &exclude_list).await;
-                    }
-                }
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_sync::handle_receive_slot()",
-                        "error processing finalized slot: {}",
-                        e
-                    );
-                }
-            };
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolSync {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(target: "consensus::protocol_sync::start()", "START");
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman.clone().spawn(self.clone().handle_receive_request(), executor.clone()).await;
-        self.jobsman
-            .clone()
-            .spawn(self.clone().handle_receive_slot_request(), executor.clone())
-            .await;
-        self.jobsman.clone().spawn(self.clone().handle_receive_block(), executor.clone()).await;
-        self.jobsman.clone().spawn(self.clone().handle_receive_slot(), executor.clone()).await;
-        debug!(target: "consensus::protocol_sync::start()", "END");
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolSync"
-    }
-}

+ 0 - 206
src/consensus/proto/protocol_sync_consensus.rs

@@ -1,206 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::sync::Arc;
-
-use async_trait::async_trait;
-use log::{debug, error};
-use smol::Executor;
-
-use crate::{
-    consensus::{
-        state::{ConsensusRequest, ConsensusResponse, ConsensusSyncRequest, ConsensusSyncResponse},
-        ValidatorStatePtr,
-    },
-    net::{
-        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
-        ProtocolJobsManager, ProtocolJobsManagerPtr,
-    },
-    Result,
-};
-
-pub struct ProtocolSyncConsensus {
-    channel: ChannelPtr,
-    request_sub: MessageSubscription<ConsensusRequest>,
-    sync_request_sub: MessageSubscription<ConsensusSyncRequest>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-}
-
-impl ProtocolSyncConsensus {
-    pub async fn init(
-        channel: ChannelPtr,
-        state: ValidatorStatePtr,
-        _p2p: P2pPtr,
-    ) -> Result<ProtocolBasePtr> {
-        let msg_subsystem = channel.message_subsystem();
-        msg_subsystem.add_dispatch::<ConsensusRequest>().await;
-        msg_subsystem.add_dispatch::<ConsensusSyncRequest>().await;
-
-        let request_sub = channel.subscribe_msg::<ConsensusRequest>().await?;
-        let sync_request_sub = channel.subscribe_msg::<ConsensusSyncRequest>().await?;
-
-        Ok(Arc::new(Self {
-            channel: channel.clone(),
-            request_sub,
-            sync_request_sub,
-            jobsman: ProtocolJobsManager::new("SyncConsensusProtocol", channel),
-            state,
-        }))
-    }
-
-    async fn handle_receive_request(self: Arc<Self>) -> Result<()> {
-        debug!(
-            target: "consensus::protocol_sync_consensus::handle_receive_request()",
-            "START"
-        );
-        loop {
-            let req = match self.request_sub.receive().await {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_sync_consensus::handle_receive_request()",
-                        "recv fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-
-            debug!(
-                target: "consensus::protocol_sync_consensus::handle_receive_request()",
-                "received {:?}",
-                req
-            );
-
-            // Extra validations can be added here.
-            let lock = self.state.read().await;
-            let bootstrap_slot = lock.consensus.bootstrap_slot;
-            let current_slot = lock.consensus.time_keeper.current_slot();
-            let mut forks = vec![];
-            for fork in &lock.consensus.forks {
-                forks.push(fork.clone().into());
-            }
-            let pending_txs = match lock.blockchain.get_pending_txs() {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_sync_consensus::handle_receive_request()",
-                        "Failed querying pending txs store: {}",
-                        e
-                    );
-                    vec![]
-                }
-            };
-            let slots = lock.consensus.slots.clone();
-            let mut f_history = vec![];
-            for f in &lock.consensus.f_history {
-                let f_str = format!("{:}", f);
-                f_history.push(f_str);
-            }
-            let mut err_history = vec![];
-            for err in &lock.consensus.err_history {
-                let err_str = format!("{:}", err);
-                err_history.push(err_str);
-            }
-            let nullifiers = lock.consensus.nullifiers.clone();
-            let response = ConsensusResponse {
-                bootstrap_slot,
-                current_slot,
-                forks,
-                pending_txs,
-                slots,
-                f_history,
-                err_history,
-                nullifiers,
-            };
-            if let Err(e) = self.channel.send(&response).await {
-                error!(
-                    target: "consensus::protocol_sync_consensus::handle_receive_request()",
-                    "channel send fail: {}",
-                    e
-                );
-            };
-        }
-    }
-
-    async fn handle_receive_sync_request(self: Arc<Self>) -> Result<()> {
-        debug!(
-            target: "consensus::protocol_sync_consensus::handle_receive_sync_request()",
-            "START"
-        );
-        loop {
-            let req = match self.sync_request_sub.receive().await {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_sync_consensus::handle_receive_sync_request()",
-                        "recv fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-
-            debug!(
-                target: "consensus::protocol_sync_consensus::handle_receive_sync_request()",
-                "received {:?}",
-                req
-            );
-
-            // Extra validations can be added here.
-            let lock = self.state.read().await;
-            let bootstrap_slot = lock.consensus.bootstrap_slot;
-            let proposing = lock.consensus.proposing;
-            let is_empty = lock.consensus.slots_is_empty();
-            let response = ConsensusSyncResponse { bootstrap_slot, proposing, is_empty };
-            if let Err(e) = self.channel.send(&response).await {
-                error!(
-                    target: "consensus::protocol_sync_consensus::handle_receive_sync_request()",
-                    "channel send fail: {}",
-                    e
-                );
-            };
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolSyncConsensus {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(
-            target: "consensus::protocol_sync_consensus::start()",
-            "START"
-        );
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman.clone().spawn(self.clone().handle_receive_request(), executor.clone()).await;
-        self.jobsman
-            .clone()
-            .spawn(self.clone().handle_receive_sync_request(), executor.clone())
-            .await;
-        debug!(
-            target: "consensus::protocol_sync_consensus::start()",
-            "END"
-        );
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolSyncConsensus"
-    }
-}

+ 0 - 122
src/consensus/proto/protocol_tx.rs

@@ -1,122 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::sync::Arc;
-
-use async_trait::async_trait;
-use log::debug;
-use smol::Executor;
-use url::Url;
-
-use crate::{
-    consensus::ValidatorStatePtr,
-    impl_p2p_message,
-    net::{
-        ChannelPtr, Message, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
-        ProtocolJobsManager, ProtocolJobsManagerPtr,
-    },
-    tx::Transaction,
-    Result,
-};
-
-impl_p2p_message!(Transaction, "tx");
-
-pub struct ProtocolTx {
-    tx_sub: MessageSubscription<Transaction>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-    p2p: P2pPtr,
-    channel_address: Url,
-}
-
-impl ProtocolTx {
-    pub async fn init(
-        channel: ChannelPtr,
-        state: ValidatorStatePtr,
-        p2p: P2pPtr,
-    ) -> Result<ProtocolBasePtr> {
-        debug!(
-            target: "consensus::protocol_tx::init()",
-            "Adding ProtocolTx to the protocol registry"
-        );
-        let msg_subsystem = channel.message_subsystem();
-        msg_subsystem.add_dispatch::<Transaction>().await;
-
-        let tx_sub = channel.subscribe_msg::<Transaction>().await?;
-
-        Ok(Arc::new(Self {
-            tx_sub,
-            jobsman: ProtocolJobsManager::new("TxProtocol", channel.clone()),
-            state,
-            p2p,
-            channel_address: channel.address().clone(),
-        }))
-    }
-
-    async fn handle_receive_tx(self: Arc<Self>) -> Result<()> {
-        debug!(
-            target: "consensus::protocol_tx::handle_receive_tx()",
-            "START"
-        );
-        let exclude_list = vec![self.channel_address.clone()];
-        loop {
-            let tx = match self.tx_sub.receive().await {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(
-                        target: "consensus::protocol_tx::handle_receive_tx()",
-                        "recv fail: {}",
-                        e
-                    );
-                    continue
-                }
-            };
-
-            // Check if node has finished syncing its blockchain
-            if !self.state.read().await.synced {
-                debug!(
-                    target: "consensus::protocol_tx::handle_receive_tx()",
-                    "Node still syncing blockchain, skipping..."
-                );
-                continue
-            }
-
-            let tx_copy = (*tx).clone();
-
-            // Nodes use unconfirmed_txs vector as seen_txs pool.
-            if self.state.write().await.append_tx(tx_copy.clone()).await {
-                self.p2p.broadcast_with_exclude(&tx_copy, &exclude_list).await;
-            }
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolTx {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(target: "consensus::protocol_tx::start()", "START");
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman.clone().spawn(self.clone().handle_receive_tx(), executor.clone()).await;
-        debug!(target: "consensus::protocol_tx::start()", "END");
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolTx"
-    }
-}

+ 0 - 95
src/consensus/rcpt.rs

@@ -1,95 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use crypto_api_chachapoly::ChachaPolyIetf;
-use darkfi_sdk::{
-    crypto::{
-        diffie_hellman::{kdf_sapling, sapling_ka_agree},
-        keypair::PublicKey,
-        SecretKey,
-    },
-    pasta::pallas,
-};
-use darkfi_serial::{async_trait, Decodable, Encodable, SerialDecodable, SerialEncodable};
-use rand::rngs::OsRng;
-
-use crate::Error;
-
-/// transfered lead coin is rcpt into two coins,
-/// first coin is transfered rcpt coin.
-/// second coin is the change returning to sender, or different address.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct TxRcpt {
-    /// rcpt coin nonce
-    pub rho: pallas::Base,
-    /// rcpt coin commitment opening
-    pub opening: pallas::Scalar,
-    /// rcpt coin value
-    pub value: u64,
-}
-
-pub const PLAINTEXT_SIZE: usize = 32 + 32 + 8;
-pub const AEAD_TAG_SIZE: usize = 16;
-pub const CIPHER_SIZE: usize = PLAINTEXT_SIZE + AEAD_TAG_SIZE;
-
-impl TxRcpt {
-    /// encrypt received coin, by recipient public key
-    pub fn encrypt(&self, public: &PublicKey) -> EncryptedTxRcpt {
-        let ephem_secret = SecretKey::random(&mut OsRng);
-        let ephem_public = PublicKey::from_secret(ephem_secret);
-        let shared_secret = sapling_ka_agree(&ephem_secret, public);
-        let key = kdf_sapling(&shared_secret, &ephem_public);
-
-        let mut input = Vec::new();
-        self.encode(&mut input).unwrap();
-
-        let mut ciphertext = [0u8; CIPHER_SIZE];
-        assert_eq!(
-            ChachaPolyIetf::aead_cipher()
-                .seal_to(&mut ciphertext, &input, &[], key.as_ref(), &[0u8; 12])
-                .unwrap(),
-            CIPHER_SIZE
-        );
-
-        EncryptedTxRcpt { ciphertext, ephem_public }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct EncryptedTxRcpt {
-    ciphertext: [u8; CIPHER_SIZE],
-    ephem_public: PublicKey,
-}
-
-impl EncryptedTxRcpt {
-    pub fn decrypt(&self, secret: &SecretKey) -> TxRcpt {
-        let shared_secret = sapling_ka_agree(secret, &self.ephem_public);
-        let key = kdf_sapling(&shared_secret, &self.ephem_public);
-
-        let mut plaintext = [0; CIPHER_SIZE];
-        assert_eq!(
-            ChachaPolyIetf::aead_cipher()
-                .open_to(&mut plaintext, &self.ciphertext, &[], key.as_ref(), &[0u8; 12])
-                .map_err(|_| Error::TxRcptDecryptionError)
-                .unwrap(),
-            PLAINTEXT_SIZE
-        );
-
-        TxRcpt::decode(&plaintext[..]).unwrap()
-    }
-}

+ 0 - 898
src/consensus/state.rs

@@ -1,898 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::{
-    blockchain::{PidOutput, PreviousSlot, Slot},
-    crypto::MerkleTree,
-    pasta::{group::ff::PrimeField, pallas},
-};
-use darkfi_serial::{async_trait, deserialize, serialize, SerialDecodable, SerialEncodable};
-use log::info;
-use rand::{thread_rng, Rng};
-
-use super::{
-    constants,
-    lead_coin::{LeadCoin, LeadCoinSecrets},
-    utils::fbig2base,
-    Block, BlockProposal, Float10,
-};
-use crate::{
-    blockchain::Blockchain,
-    impl_p2p_message,
-    net::Message,
-    tx::Transaction,
-    util::time::{TimeKeeper, Timestamp},
-    wallet::WalletPtr,
-    Error, Result,
-};
-
-use std::{
-    fs::File,
-    io::{prelude::*, BufWriter},
-};
-
-/// This struct represents the information required by the consensus algorithm
-pub struct ConsensusState {
-    /// Wallet interface
-    pub wallet: WalletPtr,
-    /// Canonical (finalized) blockchain
-    pub blockchain: Blockchain,
-    /// Network bootstrap timestamp
-    pub bootstrap_ts: Timestamp,
-    /// Helper structure to calculate time related operations
-    pub time_keeper: TimeKeeper,
-    /// Genesis block hash
-    pub genesis_block: blake3::Hash,
-    /// Total sum of initial staking coins
-    pub initial_distribution: u64,
-    /// Flag to enable single-node mode
-    pub single_node: bool,
-    /// Slot the network was bootstrapped
-    pub bootstrap_slot: u64,
-    /// Participating start slot
-    pub participating: Option<u64>,
-    /// Node is able to propose proposals
-    pub proposing: bool,
-    /// Last slot node check for finalization
-    pub checked_finalization: u64,
-    /// Fork chains containing block proposals
-    pub forks: Vec<Fork>,
-    /// Current epoch
-    pub epoch: u64,
-    /// Hot/live slots
-    pub slots: Vec<Slot>,
-    /// Last slot leaders count
-    pub previous_leaders: u64,
-    /// Controller output history
-    pub f_history: Vec<Float10>,
-    /// Controller proportional error history
-    pub err_history: Vec<Float10>,
-    // TODO: Aren't these already in db after finalization?
-    /// Canonical competing coins
-    pub coins: Vec<LeadCoin>,
-    /// Canonical coin commitments tree
-    pub coins_tree: MerkleTree,
-    /// Canonical seen nullifiers from proposals
-    pub nullifiers: Vec<pallas::Base>,
-}
-
-impl ConsensusState {
-    pub fn new(
-        wallet: WalletPtr,
-        blockchain: Blockchain,
-        bootstrap_ts: Timestamp,
-        genesis_ts: Timestamp,
-        genesis_data: blake3::Hash,
-        initial_distribution: u64,
-        single_node: bool,
-    ) -> Self {
-        let genesis_block = Block::genesis_block(genesis_ts, genesis_data).blockhash();
-        let time_keeper =
-            TimeKeeper::new(genesis_ts, constants::EPOCH_LENGTH as u64, constants::SLOT_TIME, 0);
-        Self {
-            wallet,
-            blockchain,
-            bootstrap_ts,
-            time_keeper,
-            genesis_block,
-            initial_distribution,
-            single_node,
-            bootstrap_slot: 0,
-            participating: None,
-            proposing: false,
-            checked_finalization: 0,
-            forks: vec![],
-            epoch: 0,
-            slots: vec![],
-            previous_leaders: 0,
-            f_history: vec![constants::FLOAT10_ZERO.clone()],
-            err_history: vec![constants::FLOAT10_ZERO.clone(), constants::FLOAT10_ZERO.clone()],
-            coins: vec![],
-            coins_tree: MerkleTree::new(constants::EPOCH_LENGTH * 100),
-            nullifiers: vec![],
-        }
-    }
-
-    /// Finds the last slot a proposal or block was generated.
-    pub fn last_slot(&self) -> Result<u64> {
-        let mut slot = 0;
-        for chain in &self.forks {
-            for state_checkpoint in &chain.sequence {
-                if state_checkpoint.proposal.block.header.slot > slot {
-                    slot = state_checkpoint.proposal.block.header.slot;
-                }
-            }
-        }
-
-        // We return here in case proposals exist,
-        // so we don't query the sled database.
-        if slot > 0 {
-            return Ok(slot)
-        }
-
-        let (last_slot, _) = self.blockchain.last()?;
-        Ok(last_slot)
-    }
-
-    /// Set participating slot to next.
-    pub fn set_participating(&mut self) -> Result<()> {
-        self.participating = Some(self.time_keeper.current_slot() + 1);
-        Ok(())
-    }
-
-    /// Generate current slot
-    fn generate_slot(
-        &mut self,
-        fork_hashes: Vec<blake3::Hash>,
-        fork_previous_hashes: Vec<blake3::Hash>,
-        sigma1: pallas::Base,
-        sigma2: pallas::Base,
-    ) {
-        let id = self.time_keeper.current_slot();
-        let previous = PreviousSlot::new(0, fork_hashes, fork_previous_hashes, 0.0);
-        let pid = PidOutput::new(0.0, 0.0, sigma1, sigma2);
-        let slot = Slot::new(id, previous, pid, self.get_last_eta(), 0, 0);
-        info!(target: "consensus::state", "generate_slot: {:?}", slot);
-        self.slots.push(slot);
-    }
-
-    // Initialize node lead coins and set current epoch and eta.
-    pub async fn init_coins(&mut self) -> Result<()> {
-        self.epoch = self.time_keeper.current_epoch();
-        self.coins = self.create_coins().await?;
-        self.update_forks_checkpoints();
-        Ok(())
-    }
-
-    /// Check if new epoch has started and generate slot.
-    /// Returns flag to signify if epoch has changed.
-    pub async fn epoch_changed(
-        &mut self,
-        fork_hashes: Vec<blake3::Hash>,
-        fork_previous_hashes: Vec<blake3::Hash>,
-        sigma1: pallas::Base,
-        sigma2: pallas::Base,
-    ) -> Result<bool> {
-        self.generate_slot(fork_hashes, fork_previous_hashes, sigma1, sigma2);
-        let epoch = self.time_keeper.current_epoch();
-        if epoch <= self.epoch {
-            return Ok(false)
-        }
-        self.epoch = epoch;
-
-        Ok(true)
-    }
-
-    /// Return 2-term target approximation sigma coefficients.
-    pub fn sigmas(&mut self) -> (pallas::Base, pallas::Base) {
-        let f = self.win_inv_prob_with_full_stake();
-        let total_stake = self.total_stake();
-        let total_sigma = Float10::try_from(total_stake).unwrap();
-        self.calc_sigmas(f, total_sigma)
-    }
-
-    fn calc_sigmas(&self, f: Float10, total_sigma: Float10) -> (pallas::Base, pallas::Base) {
-        info!(target: "consensus::state", "sigmas(): f: {}", f);
-        info!(target: "consensus::state", "sigmas(): total network stake: {:}", total_sigma);
-
-        let one = constants::FLOAT10_ONE.clone();
-        let neg_one = constants::FLOAT10_NEG_ONE.clone();
-        let two = constants::FLOAT10_TWO.clone();
-
-        let field_p = Float10::try_from(constants::P).unwrap();
-
-        let x = one - f;
-        let c = x.ln();
-        let neg_c = neg_one * c;
-
-        let sigma1_fbig = neg_c.clone() /
-            (total_sigma.clone() + constants::FLOAT10_EPSILON.clone()) *
-            field_p.clone();
-        info!(target: "consensus::state", "sigma1_fbig: {:}", sigma1_fbig);
-        let sigma1 = fbig2base(sigma1_fbig);
-
-        let sigma2_fbig = (neg_c / (total_sigma + constants::FLOAT10_EPSILON.clone()))
-            .powf(two.clone()) *
-            (field_p / two);
-        info!(target: "consensus::state", "sigma2_fbig: {:}", sigma2_fbig);
-        let sigma2 = fbig2base(sigma2_fbig);
-
-        (sigma1, sigma2)
-    }
-
-    /// Generate coins for provided sigmas.
-    /// NOTE: The strategy here is having a single competing coin per slot.
-    // TODO: DRK coin need to be burned, and consensus coin to be minted.
-    async fn create_coins(&mut self) -> Result<Vec<LeadCoin>> {
-        // TODO: cleanup LeadCoinSecrets, no need to keep a vector
-        let (seeds, epoch_secrets) = {
-            let mut rng = thread_rng();
-            let mut seeds: Vec<u64> = Vec::with_capacity(constants::EPOCH_LENGTH);
-            for _ in 0..constants::EPOCH_LENGTH {
-                seeds.push(rng.gen());
-            }
-            (seeds, LeadCoinSecrets::generate())
-        };
-
-        // LeadCoin matrix containing node competing coins.
-        let mut coins: Vec<LeadCoin> = Vec::with_capacity(constants::EPOCH_LENGTH);
-
-        // Retrieve coin from wallet
-        // NOTE: In future this will be retrieved from the money contract.
-
-        // Execute the query and see if we find any rows
-        let query_str = format!("SELECT * FROM {}", constants::CONSENSUS_COIN_TABLE);
-        let wallet_conn = self.wallet.conn.lock().await;
-        let mut stmt = wallet_conn.prepare(&query_str)?;
-
-        let coin = stmt.query_row((), |row| {
-            let bytes: Vec<u8> = row.get(constants::CONSENSUS_COIN_COL)?;
-            let coin = deserialize(&bytes).unwrap();
-            Ok(coin)
-        });
-
-        stmt.finalize()?;
-
-        let coin = match coin {
-            Ok(c) => c,
-            Err(_) => {
-                // If no records are found, we generate a new coin and save it to the database
-                info!(target: "consensus::state", "create_coins(): No LeadCoin was found in DB, generating new one...");
-                // Temporarily, we compete with fixed stake.
-                // This stake should be based on how many nodes we want to run, and they all
-                // must sum to initial distribution total coins.
-                //let stake = self.initial_distribution;
-                let c = LeadCoin::new(
-                    0,
-                    self.time_keeper.current_slot(),
-                    epoch_secrets.secret_keys[0].inner(),
-                    epoch_secrets.merkle_roots[0],
-                    0,
-                    epoch_secrets.merkle_paths[0].clone(),
-                    pallas::Base::from(seeds[0]),
-                    &mut self.coins_tree,
-                );
-                let query_str = format!(
-                    "INSERT INTO {} ({}) VALUES (?1);",
-                    constants::CONSENSUS_COIN_TABLE,
-                    constants::CONSENSUS_COIN_COL
-                );
-                let mut stmt = wallet_conn.prepare(&query_str)?;
-                stmt.execute([serialize(&c)])?;
-                c
-            }
-        };
-
-        info!(target: "consensus::state", "create_coins(): Will use LeadCoin with value: {}", coin.value);
-        coins.push(coin);
-
-        Ok(coins)
-    }
-
-    /// Leadership reward, assuming constant reward
-    /// TODO (res) implement reward mechanism with accord to DRK,DARK token-economics
-    fn reward(&self) -> u64 {
-        constants::REWARD
-    }
-
-    /// Auxillary function to calculate total slot rewards.
-    fn slot_rewards(&self) -> u64 {
-        // Retrieve existing blocks excluding genesis
-        let blocks = (self.blockchain.len() as u64) - 1;
-        // Retrieve longest fork length, to include those proposals in the calculation
-        let max_fork_length = self.longest_chain_length() as u64;
-        // Calculate rewarded slots
-        let rewarded_slots = blocks + max_fork_length;
-
-        rewarded_slots * self.reward()
-    }
-
-    /// Network total stake, assuming constant reward.
-    /// Only used for fine-tuning. At genesis epoch first slot, of absolute index 0,
-    /// if no stake was distributed, the total stake would be 0.
-    /// To avoid division by zero, we asume total stake at first division is GENESIS_TOTAL_STAKE(1).
-    fn total_stake(&self) -> u64 {
-        let total_stake = self.slot_rewards() + self.initial_distribution;
-        if total_stake == 0 {
-            return constants::GENESIS_TOTAL_STAKE
-        }
-        total_stake
-    }
-
-    fn f_err(&mut self) -> Float10 {
-        info!(target: "consensus::state", "Previous leaders: {}", self.previous_leaders);
-        // Write counter to file
-        let mut count_str: String = self.previous_leaders.to_string();
-        count_str.push(',');
-        let f =
-            File::options().append(true).create(true).open(constants::LEADER_HISTORY_LOG).unwrap();
-        {
-            let mut writer = BufWriter::new(f);
-            let _ = writer.write(&count_str.into_bytes()).unwrap();
-        }
-        // Calculate feedback
-        let feedback = Float10::try_from(self.previous_leaders as i64).unwrap();
-        // Reset previous leaders counter
-        self.previous_leaders = 0;
-        let target = constants::FLOAT10_ONE.clone();
-        target - feedback
-    }
-
-    fn discrete_pid(&mut self) -> Float10 {
-        let k1 = constants::KP.clone() + constants::KI.clone() + constants::KD.clone();
-        let k2 = constants::FLOAT10_NEG_ONE.clone() * constants::KP.clone() +
-            constants::FLOAT10_NEG_TWO.clone() * constants::KD.clone();
-        let k3 = constants::KD.clone();
-        let f_len = self.f_history.len();
-        let err = self.f_err();
-        let err_len = self.err_history.len();
-        let ret = self.f_history[f_len - 1].clone() +
-            k1.clone() * err.clone() +
-            k2.clone() * self.err_history[err_len - 1].clone() +
-            k3.clone() * self.err_history[err_len - 2].clone();
-        info!(target: "consensus::state", "pid::f-1: {:}", self.f_history[f_len - 1].clone());
-        info!(target: "consensus::state", "pid::err: {:}", err);
-        info!(target: "consensus::state", "pid::err-1: {}", self.err_history[err_len - 1].clone());
-        info!(target: "consensus::state", "pid::err-2: {}", self.err_history[err_len - 2].clone());
-        info!(target: "consensus::state", "pid::k1: {}", k1);
-        info!(target: "consensus::state", "pid::k2: {}", k2);
-        info!(target: "consensus::state", "pid::k3: {}", k3);
-        self.err_history.push(err);
-        ret
-    }
-    /// the probability inverse of winning lottery having all the stake
-    /// returns f
-    fn win_inv_prob_with_full_stake(&mut self) -> Float10 {
-        let mut f = self.discrete_pid();
-        if f <= constants::FLOAT10_ZERO.clone() {
-            f = constants::MIN_F.clone()
-        } else if f >= constants::FLOAT10_ONE.clone() {
-            f = constants::MAX_F.clone()
-        }
-        // log f history
-        let file =
-            File::options().append(true).create(true).open(constants::F_HISTORY_LOG).unwrap();
-        {
-            let mut f_history = format!("{:}", f);
-            f_history.push(',');
-            let mut writer = BufWriter::new(file);
-            let _ = writer.write(&f_history.into_bytes()).unwrap();
-        }
-        self.f_history.push(f.clone());
-        f
-    }
-
-    /// Check that the participant/stakeholder coins win the slot lottery.
-    /// If the stakeholder has multiple competing winning coins, only the highest value
-    /// coin is selected, since the stakeholder can't give more than one proof per block/slot.
-    /// * 'sigma1', 'sigma2': slot sigmas
-    /// Returns: (check: bool, idx: usize) where idx is the winning coin's index
-    pub fn is_slot_leader(
-        &mut self,
-        sigma1: pallas::Base,
-        sigma2: pallas::Base,
-    ) -> (bool, i64, usize) {
-        // Check if node can produce proposals
-        if !self.proposing {
-            return (false, 0, 0)
-        }
-
-        let fork_index = self.longest_chain_index();
-        let competing_coins = if fork_index == -1 {
-            self.coins.clone()
-        } else {
-            self.forks[fork_index as usize].sequence.last().unwrap().coins.clone()
-        };
-
-        // If on single-node mode, node always proposes by extending the
-        // single fork it holds.
-        if self.single_node {
-            return (true, fork_index, 0)
-        }
-
-        let mut won = false;
-        let mut highest_stake = 0;
-        let mut highest_stake_idx = 0;
-        let total_stake = self.total_stake();
-        for (winning_idx, coin) in competing_coins.iter().enumerate() {
-            info!(target: "consensus::state", "is_slot_leader: coin stake: {:?}", coin.value);
-            info!(target: "consensus::state", "is_slot_leader: total stake: {}", total_stake);
-            info!(target: "consensus::state", "is_slot_leader: relative stake: {}", (coin.value as f64) / total_stake as f64);
-
-            let first_winning = coin.is_leader(
-                sigma1,
-                sigma2,
-                self.get_last_eta(),
-                pallas::Base::from(self.time_keeper.current_slot()),
-            );
-
-            if first_winning && !won {
-                highest_stake_idx = winning_idx;
-            }
-
-            won |= first_winning;
-            if won && coin.value > highest_stake {
-                highest_stake = coin.value;
-                highest_stake_idx = winning_idx;
-            }
-        }
-
-        (won, fork_index, highest_stake_idx)
-    }
-
-    /// Finds the longest forkchain the node holds and
-    /// returns its index.
-    pub fn longest_chain_index(&self) -> i64 {
-        let mut length = 0;
-        let mut index = -1;
-
-        if !self.forks.is_empty() {
-            for (i, chain) in self.forks.iter().enumerate() {
-                if chain.sequence.len() > length {
-                    length = chain.sequence.len();
-                    index = i as i64;
-                }
-            }
-        }
-
-        index
-    }
-
-    /// Finds the length of longest fork chain the node holds.
-    pub fn longest_chain_length(&self) -> usize {
-        let mut max = 0;
-        for fork in &self.forks {
-            if fork.sequence.len() > max {
-                max = fork.sequence.len();
-            }
-        }
-
-        max
-    }
-
-    /// Given a proposal, find the index of the fork chain it extends.
-    pub fn find_extended_chain_index(&mut self, proposal: &BlockProposal) -> Result<i64> {
-        // We iterate through all forks to find which fork to extend
-        let mut chain_index = -1;
-        let mut state_checkpoint_index = 0;
-        for (c_index, chain) in self.forks.iter().enumerate() {
-            // Traverse sequence in reverse
-            for (sc_index, state_checkpoint) in chain.sequence.iter().enumerate().rev() {
-                if proposal.block.header.previous == state_checkpoint.proposal.hash {
-                    chain_index = c_index as i64;
-                    state_checkpoint_index = sc_index;
-                    break
-                }
-            }
-            if chain_index != -1 {
-                break
-            }
-        }
-
-        // If no fork was found, we check with canonical
-        if chain_index == -1 {
-            let (last_slot, last_block) = self.blockchain.last()?;
-            if proposal.block.header.previous != last_block ||
-                proposal.block.header.slot <= last_slot
-            {
-                info!(target: "consensus::state", "find_extended_chain_index(): Proposal doesn't extend any known chain");
-                return Ok(-2)
-            }
-
-            // Proposal extends canonical chain
-            return Ok(-1)
-        }
-
-        // Found fork chain
-        let chain = &self.forks[chain_index as usize];
-        // Proposal extends fork at last proposal
-        if state_checkpoint_index == (chain.sequence.len() - 1) {
-            return Ok(chain_index)
-        }
-
-        info!(target: "consensus::state", "find_extended_chain_index(): Proposal to fork a forkchain was received.");
-        let mut chain = self.forks[chain_index as usize].clone();
-        // We keep all proposals until the one it extends
-        chain.sequence.drain((state_checkpoint_index + 1)..);
-        self.forks.push(chain);
-        Ok(self.forks.len() as i64 - 1)
-    }
-
-    /// Search the chains we're holding for the given proposal.
-    pub fn proposal_exists(&self, input_proposal: &blake3::Hash) -> bool {
-        for chain in self.forks.iter() {
-            for state_checkpoint in chain.sequence.iter().rev() {
-                if input_proposal == &state_checkpoint.proposal.hash {
-                    return true
-                }
-            }
-        }
-
-        false
-    }
-
-    /// Utility function to extract leader selection lottery randomness(eta),
-    /// defined as the hash of the last block, converted to pallas base.
-    pub fn get_last_eta(&self) -> pallas::Base {
-        let (_, hash) = self.blockchain.last().unwrap();
-        let mut bytes: [u8; 32] = *hash.as_bytes();
-        // Read first 254 bits
-        bytes[30] = 0;
-        bytes[31] = 0;
-        pallas::Base::from_repr(bytes).unwrap()
-    }
-
-    /// Auxillary function to retrieve slot of provided slot UID.
-    pub fn get_slot(&self, id: u64) -> Result<Slot> {
-        // Check hot/live slotz
-        for slot in self.slots.iter().rev() {
-            if slot.id == id {
-                return Ok(slot.clone())
-            }
-        }
-        // Check if slot is finalized
-        if let Ok(slots) = self.blockchain.get_slots_by_id(&[id]) {
-            if !slots.is_empty() {
-                if let Some(known_slot) = &slots[0] {
-                    return Ok(known_slot.clone())
-                }
-            }
-        }
-        Err(Error::SlotNotFound(id))
-    }
-
-    /// Auxillary function to check if node has seen current or previous slots.
-    /// This check ensures that either the slots exist in memory or node has seen the finalization of these slots.
-    pub fn slots_is_empty(&self) -> bool {
-        let current_slot = self.time_keeper.current_slot();
-        if self.get_slot(current_slot).is_ok() {
-            return false
-        }
-        let previous_slot = current_slot - 1;
-        self.get_slot(previous_slot).is_err()
-    }
-
-    /// Auxillary function to update all fork state checkpoints to nodes coins current canonical states.
-    /// Note: This function should only be invoked once on nodes' coins creation.
-    pub fn update_forks_checkpoints(&mut self) {
-        for fork in &mut self.forks {
-            for state_checkpoint in &mut fork.sequence {
-                state_checkpoint.coins = self.coins.clone();
-                state_checkpoint.coins_tree = self.coins_tree.clone();
-            }
-        }
-    }
-
-    /// Retrieve current forks last proposal hashes and their previous
-    /// hashes. If node holds no fork, retrieve last canonical hash.
-    pub fn fork_hashes(&self) -> (Vec<blake3::Hash>, Vec<blake3::Hash>) {
-        let mut hashes = vec![];
-        let mut previous_hashes = vec![];
-        for fork in &self.forks {
-            let proposal = &fork.sequence.last().unwrap().proposal;
-            hashes.push(proposal.hash);
-            previous_hashes.push(proposal.block.header.previous);
-        }
-
-        if hashes.is_empty() {
-            hashes.push(self.genesis_block);
-            previous_hashes.push(self.genesis_block);
-        }
-
-        (hashes, previous_hashes)
-    }
-
-    /// Auxiliary structure to reset consensus state for a resync
-    pub fn reset(&mut self) {
-        self.participating = None;
-        self.proposing = false;
-        self.forks = vec![];
-        self.slots = vec![];
-        self.previous_leaders = 0;
-        self.f_history = vec![constants::FLOAT10_ZERO.clone()];
-        self.err_history = vec![constants::FLOAT10_ZERO.clone(), constants::FLOAT10_ZERO.clone()];
-        self.nullifiers = vec![];
-    }
-}
-
-/// Auxiliary structure used for consensus syncing.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct ConsensusRequest {}
-impl_p2p_message!(ConsensusRequest, "consensusrequest");
-
-/// Auxiliary structure used for consensus syncing.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct ConsensusResponse {
-    /// Slot the network was bootstrapped
-    pub bootstrap_slot: u64,
-    /// Current slot
-    pub current_slot: u64,
-    /// Hot/live data used by the consensus algorithm
-    pub forks: Vec<ForkInfo>,
-    /// Pending transactions
-    pub pending_txs: Vec<Transaction>,
-    /// Hot/live slots
-    pub slots: Vec<Slot>,
-    // TODO: When Float10 supports encoding/decoding this should be
-    // replaced by directly using Vec<Float10>
-    /// Controller output history
-    pub f_history: Vec<String>,
-    /// Controller proportional error history
-    pub err_history: Vec<String>,
-    /// Seen nullifiers from proposals
-    pub nullifiers: Vec<pallas::Base>,
-}
-
-impl_p2p_message!(ConsensusResponse, "consensusresponse");
-
-/// Auxiliary structure used for consensus syncing.
-#[derive(Debug, SerialEncodable, SerialDecodable)]
-pub struct ConsensusSyncRequest {}
-
-impl_p2p_message!(ConsensusSyncRequest, "consensussyncrequest");
-
-/// Auxiliary structure used for consensus syncing.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct ConsensusSyncResponse {
-    /// Node known bootstrap slot
-    pub bootstrap_slot: u64,
-    /// Node is able to propose proposals
-    pub proposing: bool,
-    /// Node has hot/live slots
-    pub is_empty: bool,
-}
-
-impl_p2p_message!(ConsensusSyncResponse, "consensussyncresponse");
-impl_p2p_message!(Slot, "slot");
-
-/// Auxiliary structure used for slots syncing
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct SlotRequest {
-    /// Slot UID
-    pub slot: u64,
-}
-
-impl_p2p_message!(SlotRequest, "slotrequest");
-
-/// Auxiliary structure used for slots syncing
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct SlotResponse {
-    /// Response blocks.
-    pub slots: Vec<Slot>,
-}
-
-impl_p2p_message!(SlotResponse, "slotresponse");
-
-/// Auxiliary structure used to keep track of consensus state checkpoints.
-#[derive(Debug, Clone)]
-pub struct StateCheckpoint {
-    /// Block proposal
-    pub proposal: BlockProposal,
-    /// Node competing coins current state
-    pub coins: Vec<LeadCoin>,
-    /// Coin commitments tree current state
-    pub coins_tree: MerkleTree,
-    /// Seen nullifiers from proposals current state
-    pub nullifiers: Vec<pallas::Base>,
-}
-
-impl StateCheckpoint {
-    pub fn new(
-        proposal: BlockProposal,
-        coins: Vec<LeadCoin>,
-        coins_tree: MerkleTree,
-        nullifiers: Vec<pallas::Base>,
-    ) -> Self {
-        Self { proposal, coins, coins_tree, nullifiers }
-    }
-}
-
-/// Auxiliary structure used for forked consensus state checkpoints syncing
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct StateCheckpointInfo {
-    /// Block proposal
-    pub proposal: BlockProposal,
-    /// Seen nullifiers from proposals current state
-    pub nullifiers: Vec<pallas::Base>,
-}
-
-impl From<StateCheckpoint> for StateCheckpointInfo {
-    fn from(state_checkpoint: StateCheckpoint) -> Self {
-        Self { proposal: state_checkpoint.proposal, nullifiers: state_checkpoint.nullifiers }
-    }
-}
-
-impl From<StateCheckpointInfo> for StateCheckpoint {
-    fn from(state_checkpoint_info: StateCheckpointInfo) -> Self {
-        Self {
-            proposal: state_checkpoint_info.proposal,
-            coins: vec![],
-            coins_tree: MerkleTree::new(constants::EPOCH_LENGTH * 100),
-            nullifiers: state_checkpoint_info.nullifiers,
-        }
-    }
-}
-
-/// This struct represents a sequence of consensus state checkpoints.
-#[derive(Debug, Clone)]
-pub struct Fork {
-    pub genesis_block: blake3::Hash,
-    pub sequence: Vec<StateCheckpoint>,
-}
-
-impl Fork {
-    pub fn new(genesis_block: blake3::Hash, initial_state_checkpoint: StateCheckpoint) -> Self {
-        Self { genesis_block, sequence: vec![initial_state_checkpoint] }
-    }
-
-    /// Insertion of a valid state checkpoint.
-    pub fn add(&mut self, state_checkpoint: &StateCheckpoint) {
-        if self.check_state_checkpoint(state_checkpoint, self.sequence.last().unwrap()) {
-            self.sequence.push(state_checkpoint.clone());
-        }
-    }
-
-    /// A fork chain is considered valid when every state checkpoint is valid,
-    /// based on the `check_state_checkpoint` function
-    pub fn check_chain(&self) -> bool {
-        for (index, state_checkpoint) in self.sequence[1..].iter().enumerate() {
-            if !self.check_state_checkpoint(state_checkpoint, &self.sequence[index]) {
-                return false
-            }
-        }
-
-        true
-    }
-
-    /// A state checkpoint is considered valid when its proposal parent hash is equal to the
-    /// hash of the previous checkpoint's proposal and their slots are incremental,
-    /// excluding the genesis block proposal.
-    pub fn check_state_checkpoint(
-        &self,
-        state_checkpoint: &StateCheckpoint,
-        previous: &StateCheckpoint,
-    ) -> bool {
-        if state_checkpoint.proposal.block.header.previous == self.genesis_block {
-            info!(target: "consensus::state", "check_checkpoint(): Genesis block proposal provided.");
-            return false
-        }
-
-        if state_checkpoint.proposal.block.header.previous != previous.proposal.hash ||
-            state_checkpoint.proposal.block.header.slot <= previous.proposal.block.header.slot
-        {
-            info!(target: "consensus::state", "check_checkpoint(): Provided state checkpoint proposal is invalid.");
-            return false
-        }
-
-        // TODO: validate rest checkpoint info(like nullifiers)
-
-        true
-    }
-}
-
-/// Auxiliary structure used for forks syncing
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct ForkInfo {
-    pub genesis_block: blake3::Hash,
-    pub sequence: Vec<StateCheckpointInfo>,
-}
-
-impl From<Fork> for ForkInfo {
-    fn from(fork: Fork) -> Self {
-        let mut sequence = vec![];
-        for state_checkpoint in fork.sequence {
-            sequence.push(state_checkpoint.into());
-        }
-        Self { genesis_block: fork.genesis_block, sequence }
-    }
-}
-
-impl From<ForkInfo> for Fork {
-    fn from(fork_info: ForkInfo) -> Self {
-        let mut sequence = vec![];
-        for checkpoint in fork_info.sequence {
-            sequence.push(checkpoint.into());
-        }
-        Self { genesis_block: fork_info.genesis_block, sequence }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::{
-        consensus::{
-            state::{Blockchain, ConsensusState},
-            utils::fbig2base,
-            Float10, TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES,
-            TESTNET_GENESIS_TIMESTAMP, TESTNET_INITIAL_DISTRIBUTION,
-        },
-        wallet::WalletDb,
-    };
-
-    #[test]
-    fn calc_sigmas_test() {
-        smol::block_on(async {
-            // Generate dummy state
-            let wallet = WalletDb::new(None, None).unwrap();
-            let sled_db = sled::Config::new().temporary(true).open().unwrap();
-            let blockchain = Blockchain::new(&sled_db).unwrap();
-            let state = ConsensusState::new(
-                wallet,
-                blockchain,
-                *TESTNET_BOOTSTRAP_TIMESTAMP,
-                *TESTNET_GENESIS_TIMESTAMP,
-                *TESTNET_GENESIS_HASH_BYTES,
-                *TESTNET_INITIAL_DISTRIBUTION,
-                true,
-            );
-
-            let precision_diff = Float10::try_from(
-                "10000000000000000000000000000000000000000000000000000000000000000000000000",
-            )
-            .unwrap();
-            let precision_diff_base = fbig2base(precision_diff);
-            let f = Float10::try_from("0.01").unwrap();
-            let total_stake = Float10::try_from("100").unwrap();
-            let (sigma1, sigma2) = state.calc_sigmas(f, total_stake);
-            let sigma1_rhs = Float10::try_from(
-                "2909373465034095801035568917399197865646520818579502832252119592405565440",
-            )
-            .unwrap();
-            let sigma1_rhs_base = fbig2base(sigma1_rhs);
-            let sigma2_rhs = Float10::try_from(
-                "9137556389643100714432609642916129738741963230846798778430644027392",
-            )
-            .unwrap();
-            let sigma2_rhs_base = fbig2base(sigma2_rhs);
-            let sigma1_delta = if sigma1_rhs_base > sigma1 {
-                sigma1_rhs_base - sigma1
-            } else {
-                sigma1 - sigma1_rhs_base
-            };
-            let sigma2_delta = if sigma2_rhs_base > sigma2 {
-                sigma2_rhs_base - sigma2
-            } else {
-                sigma2 - sigma2_rhs_base
-            };
-            //note! test cases were generated by low precision python scripts.
-            //https://github.com/ertosns/lotterysim/blob/master/pallas_unittests.csv
-            assert!(sigma1_delta < precision_diff_base);
-            assert!(sigma2_delta < precision_diff_base);
-        });
-    }
-}

+ 0 - 79
src/consensus/stx.rs

@@ -1,79 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::{
-    crypto::MerkleNode,
-    pasta::{arithmetic::CurveAffine, group::Curve, pallas},
-};
-use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
-
-use crate::{
-    zk::{proof::VerifyingKey, Proof},
-    Error, Result,
-};
-
-#[derive(Debug, Clone, SerialDecodable, SerialEncodable)]
-pub struct TransferStx {
-    /// sender's coin, or coin1_commitment in zk
-    pub coin_commitment: pallas::Point,
-    /// sender's coin pk
-    pub coin_pk: pallas::Base,
-    /// sender's coin sk's root
-    pub coin_root_sk: MerkleNode,
-    /// coin3_commitment in zk
-    pub change_coin_commitment: pallas::Point,
-    /// coin4_commitment in zk
-    pub transfered_coin_commitment: pallas::Point,
-    /// nullifiers coin1_nullifier
-    pub nullifier: pallas::Base,
-    /// sk coin creation slot
-    pub slot: pallas::Base,
-    /// root to coin's commitments
-    pub root: MerkleNode,
-    /// transfer proof
-    pub proof: Proof,
-}
-
-impl TransferStx {
-    /// verify the transfer proof.
-    pub fn verify(&self, vk: VerifyingKey) -> Result<()> {
-        if self.proof.verify(&vk, &self.public_inputs()).is_err() {
-            return Err(Error::TransferTxVerification)
-        }
-        Ok(())
-    }
-
-    /// arrange public inputs from Stxfer
-    pub fn public_inputs(&self) -> Vec<pallas::Base> {
-        let cm1 = self.coin_commitment.to_affine().coordinates().unwrap();
-        let cm3 = self.change_coin_commitment.to_affine().coordinates().unwrap();
-        let cm4 = self.transfered_coin_commitment.to_affine().coordinates().unwrap();
-        vec![
-            self.coin_pk,
-            *cm1.x(),
-            *cm1.y(),
-            *cm3.x(),
-            *cm3.y(),
-            *cm4.x(),
-            *cm4.y(),
-            self.root.inner(),
-            self.coin_root_sk.inner(),
-            self.nullifier,
-        ]
-    }
-}

+ 0 - 123
src/consensus/task/block_sync.rs

@@ -1,123 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use crate::{
-    consensus::{
-        block::{BlockOrder, BlockResponse},
-        state::{SlotRequest, SlotResponse},
-        ValidatorStatePtr,
-    },
-    net, Result,
-};
-use log::{debug, info, warn};
-
-/// async task used for block syncing.
-pub async fn block_sync_task(p2p: net::P2pPtr, state: ValidatorStatePtr) -> Result<()> {
-    info!(target: "consensus::block_sync", "Starting blockchain sync...");
-    // Getting a random connected channel to ask from peers
-    match p2p.random_channel().await {
-        Some(channel) => {
-            let msg_subsystem = channel.message_subsystem();
-
-            // Communication setup for slots
-            msg_subsystem.add_dispatch::<SlotResponse>().await;
-            let slot_response_sub = channel.subscribe_msg::<SlotResponse>().await?;
-
-            // Communication setup for blocks
-            msg_subsystem.add_dispatch::<BlockResponse>().await;
-            let block_response_sub = channel.subscribe_msg::<BlockResponse>().await?;
-
-            // Node loops until both slots and blocks have been synced
-            let mut slots_synced = false;
-            let mut blocks_synced = false;
-            loop {
-                // Node sends the last known slot of the canonical blockchain
-                // and loops until the response is the same slot (used to utilize batch requests).
-                let mut last = state.read().await.blockchain.last_slot()?;
-                info!(target: "consensus::block_sync", "Last known slot: {:?}", last.id);
-
-                loop {
-                    // Node creates a `SlotRequest` and sends it
-                    let request = SlotRequest { slot: last.id };
-                    channel.send(&request).await?;
-
-                    // Node stores response data.
-                    let resp = slot_response_sub.receive().await?;
-
-                    // Verify and store retrieveds
-                    debug!(target: "consensus::block_sync", "block_sync_task(): Processing received slots");
-                    state.write().await.receive_slots(&resp.slots).await?;
-
-                    let last_received = state.read().await.blockchain.last_slot()?;
-                    info!(target: "consensus::block_sync", "Last received slot: {:?}", last_received.id);
-
-                    if last.id == last_received.id {
-                        break
-                    }
-
-                    blocks_synced = false;
-                    last = last_received;
-                }
-
-                // We force a recheck of slots after blocks have been synced
-                if blocks_synced {
-                    slots_synced = true;
-                }
-
-                // Node sends the last known block hash of the canonical blockchain
-                // and loops until the response is the same block (used to utilize
-                // batch requests).
-                let mut last = state.read().await.blockchain.last()?;
-                info!(target: "consensus::block_sync", "Last known block: {:?} - {:?}", last.0, last.1);
-
-                loop {
-                    // Node creates a `BlockOrder` and sends it
-                    let order = BlockOrder { slot: last.0, block: last.1 };
-                    channel.send(&order).await?;
-
-                    // Node stores response data.
-                    let _resp = block_response_sub.receive().await?;
-
-                    // Verify and store retrieved blocks
-                    debug!(target: "consensus::block_sync", "block_sync_task(): Processing received blocks");
-                    //state.write().await.receive_sync_blocks(&resp.blocks).await?;
-
-                    let last_received = state.read().await.blockchain.last()?;
-                    info!(target: "consensus::block_sync", "Last received block: {:?} - {:?}", last_received.0, last_received.1);
-
-                    if last == last_received {
-                        blocks_synced = true;
-                        break
-                    }
-
-                    slots_synced = false;
-                    last = last_received;
-                }
-
-                if slots_synced && blocks_synced {
-                    break
-                }
-            }
-        }
-        None => warn!(target: "consensus::block_sync", "Node is not connected to other nodes"),
-    };
-
-    state.write().await.synced = true;
-    info!(target: "consensus::block_sync", "Blockchain synced!");
-    Ok(())
-}

+ 0 - 160
src/consensus/task/consensus_sync.rs

@@ -1,160 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use log::{info, warn};
-
-use crate::{
-    consensus::{
-        state::{ConsensusRequest, ConsensusResponse, ConsensusSyncRequest, ConsensusSyncResponse},
-        Float10, ValidatorStatePtr,
-    },
-    net::P2pPtr,
-    system::sleep,
-    Result,
-};
-
-/// async task used for consensus state syncing.
-/// Returns flag if node is not connected to other peers or consensus hasn't started,
-/// so it can immediately start proposing proposals.
-pub async fn consensus_sync_task(p2p: P2pPtr, state: ValidatorStatePtr) -> Result<bool> {
-    info!(target: "consensus::consensus_sync", "Starting consensus state sync...");
-    let current_slot = state.read().await.consensus.time_keeper.current_slot();
-    // Loop through connected channels
-    let channels = p2p.channels().await;
-    if channels.is_empty() {
-        warn!(target: "consensus::consensus_sync", "Node is not connected to other nodes");
-        let mut lock = state.write().await;
-        lock.consensus.bootstrap_slot = current_slot;
-        lock.consensus.init_coins().await?;
-        info!(target: "consensus::consensus_sync", "Consensus state synced!");
-        return Ok(true)
-    }
-
-    // Node iterates the channel peers to check if at least on peer has seen slots
-    let mut peer = None;
-    for channel in channels {
-        // Communication setup
-        let msg_subsystem = channel.message_subsystem();
-        msg_subsystem.add_dispatch::<ConsensusSyncResponse>().await;
-        let response_sub = channel.subscribe_msg::<ConsensusSyncResponse>().await?;
-        // Node creates a `ConsensusSyncRequest` and sends it
-        let request = ConsensusSyncRequest {};
-        channel.send(&request).await?;
-
-        // Node checks response
-        let response = response_sub.receive().await?;
-        if response.bootstrap_slot == current_slot {
-            warn!(target: "consensus::consensus_sync", "Network was just bootstraped, checking rest nodes");
-            continue
-        }
-        if !response.proposing {
-            warn!(target: "consensus::consensus_sync", "Node is not proposing, checking rest nodes");
-            continue
-        }
-        if response.is_empty {
-            warn!(target: "consensus::consensus_sync", "Node has not seen any slots, retrying...");
-            continue
-        }
-        // Keep peer to ask for consensus state
-        peer = Some(channel.clone());
-        break
-    }
-
-    // If no peer knows about any slots, that means that the network was bootstrapped or restarted
-    // and no node has started consensus.
-    if peer.is_none() {
-        warn!(target: "consensus::consensus_sync", "No node that has seen any slots was found, or network was just boostrapped.");
-        let mut lock = state.write().await;
-        lock.consensus.bootstrap_slot = current_slot;
-        lock.consensus.init_coins().await?;
-        info!(target: "consensus::consensus_sync", "Consensus state synced!");
-        return Ok(true)
-    }
-    let peer = peer.unwrap();
-
-    // Listen for next finalization
-    info!(target: "consensus::consensus_sync", "Waiting for next finalization...");
-    let subscriber = state.read().await.subscribers.get("blocks").unwrap().clone();
-    let subscription = subscriber.sub.subscribe().await;
-    subscription.receive().await;
-    subscription.unsubscribe().await;
-
-    // After finalization occurs, sync our consensus state.
-    // This ensures that the received state always consists of 1 fork with one proposal.
-    info!(target: "consensus::consensus_sync", "Finalization signal received, requesting consensus state...");
-    // Communication setup
-    let msg_subsystem = peer.message_subsystem();
-    msg_subsystem.add_dispatch::<ConsensusResponse>().await;
-    let response_sub = peer.subscribe_msg::<ConsensusResponse>().await?;
-    // Node creates a `ConsensusRequest` and sends it
-    peer.send(&ConsensusRequest {}).await?;
-
-    // Node verifies response came from a participating node.
-    // Extra validations can be added here.
-    let mut response = response_sub.receive().await?;
-    // Verify that peer has finished finalizing forks
-    loop {
-        if !response.forks.is_empty() {
-            warn!(target: "consensus::consensus_sync", "Peer has not finished finalization, retrying...");
-            sleep(1).await;
-            peer.send(&ConsensusRequest {}).await?;
-            response = response_sub.receive().await?;
-            continue
-        }
-        break
-    }
-
-    // Verify that the node has received all finalized blocks
-    loop {
-        if !state.read().await.blockchain.has_slot_order(response.current_slot)? {
-            warn!(target: "consensus::consensus_sync", "Node has not finished finalization, retrying...");
-            sleep(1).await;
-            continue
-        }
-        break
-    }
-
-    // Node stores response data.
-    let mut lock = state.write().await;
-    let mut forks = vec![];
-    for fork in &response.forks {
-        forks.push(fork.clone().into());
-    }
-    lock.consensus.bootstrap_slot = response.bootstrap_slot;
-    lock.consensus.forks = forks;
-    lock.append_pending_txs(&response.pending_txs).await;
-    lock.consensus.slots = response.slots.clone();
-    lock.consensus.previous_leaders = 1;
-    let mut f_history = vec![];
-    for f in &response.f_history {
-        let f_float = Float10::try_from(f.as_str()).unwrap();
-        f_history.push(f_float);
-    }
-    lock.consensus.f_history = f_history;
-    let mut err_history = vec![];
-    for err in &response.err_history {
-        let err_float = Float10::try_from(err.as_str()).unwrap();
-        err_history.push(err_float);
-    }
-    lock.consensus.err_history = err_history;
-    lock.consensus.nullifiers = response.nullifiers.clone();
-    lock.consensus.init_coins().await?;
-
-    info!(target: "consensus::consensus_sync", "Consensus state synced!");
-    Ok(false)
-}

+ 0 - 28
src/consensus/task/mod.rs

@@ -1,28 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-// TODO: Handle ? with matches in these files. They should be robust.
-
-mod block_sync;
-pub use block_sync::block_sync_task;
-
-mod consensus_sync;
-pub use consensus_sync::consensus_sync_task;
-
-mod proposal;
-pub use proposal::proposal_task;

+ 0 - 335
src/consensus/task/proposal.rs

@@ -1,335 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::sync::Arc;
-
-use log::{debug, error, info, warn};
-
-use super::consensus_sync_task;
-use crate::{
-    consensus::{constants, ValidatorStatePtr},
-    net::P2pPtr,
-    system::sleep,
-    util::time::Timestamp,
-    Result,
-};
-
-/// async task used for participating in the consensus protocol
-pub async fn proposal_task(
-    consensus_p2p: P2pPtr,
-    sync_p2p: P2pPtr,
-    state: ValidatorStatePtr,
-    ex: Arc<smol::Executor<'_>>,
-) -> Result<()> {
-    // Check if network is configured to start in the future,
-    // otherwise wait for current or next slot finalization period for optimal sync conditions.
-    // NOTE: Network beign configured to start in the future should always be the case
-    // when bootstrapping or restarting a network.
-    let current_ts = Timestamp::current_time();
-    let bootstrap_ts = state.read().await.consensus.bootstrap_ts;
-    if current_ts < bootstrap_ts {
-        let diff = bootstrap_ts.0 - current_ts.0;
-        info!(target: "consensus::proposal", "consensus: Waiting for network bootstrap: {} seconds", diff);
-        sleep(diff).await;
-    } else {
-        let mut sleep_time = state.read().await.consensus.time_keeper.next_n_slot_start(1);
-        let sync_offset = constants::FINAL_SYNC_DUR;
-        loop {
-            if sleep_time > sync_offset {
-                sleep_time -= sync_offset;
-                break
-            }
-            info!(target: "consensus::proposal", "consensus: Waiting for next slot ({:?})", sleep_time);
-            sleep(sleep_time).await;
-            sleep_time = state.read().await.consensus.time_keeper.next_n_slot_start(1);
-        }
-        info!(target: "consensus::proposal", "consensus: Waiting for finalization sync period ({:?})", sleep_time);
-        sleep(sleep_time).await;
-    }
-
-    let mut retries = 0;
-    // Sync loop
-    loop {
-        // Resetting consensus state, so node can still follow the finalized blocks by
-        // the sync p2p network/protocols
-        state.write().await.consensus.reset();
-
-        // Checking sync retries
-        if retries > constants::SYNC_MAX_RETRIES {
-            error!(target: "consensus::proposal", "consensus: Node reached max sync retries ({}) due to not being able to follow up with consensus processing.", constants::SYNC_MAX_RETRIES);
-            warn!(target: "consensus::proposal", "consensus: Terminating consensus participation.");
-            break
-        }
-
-        // Node syncs its consensus state
-        match consensus_sync_task(consensus_p2p.clone(), state.clone()).await {
-            Ok(p) => {
-                // Check if node is not connected to other nodes and can
-                // start proposing immediately.
-                if p {
-                    info!(target: "consensus::proposal", "consensus: Node can start proposing!");
-                    state.write().await.consensus.proposing = p;
-                }
-            }
-            Err(e) => {
-                error!(target: "consensus::proposal", "consensus: Failed syncing consensus state: {}. Quitting consensus.", e);
-                // TODO: Perhaps notify over a channel in order to
-                // stop consensus p2p protocols.
-                return Ok(())
-            }
-        };
-
-        // Node modifies its participating slot to next.
-        match state.write().await.consensus.set_participating() {
-            Ok(()) => {
-                info!(target: "consensus::proposal", "consensus: Node will start participating in the next slot")
-            }
-            Err(e) => {
-                error!(target: "consensus::proposal", "consensus: Failed to set participation slot: {}", e)
-            }
-        }
-
-        // Record epoch we start the consensus loop
-        let start_epoch = state.read().await.consensus.time_keeper.current_epoch();
-
-        // Start executing consensus
-        consensus_loop(consensus_p2p.clone(), sync_p2p.clone(), state.clone(), ex.clone()).await;
-
-        // Reset retries counter if more epochs have passed than sync retries duration
-        let break_epoch = state.read().await.consensus.time_keeper.current_epoch();
-        if (break_epoch - start_epoch) > constants::SYNC_RETRIES_DURATION {
-            retries = 0;
-        }
-
-        // Increase retries count on consensus loop break
-        retries += 1;
-    }
-
-    Ok(())
-}
-
-/// Consensus protocol loop
-async fn consensus_loop(
-    consensus_p2p: P2pPtr,
-    sync_p2p: P2pPtr,
-    state: ValidatorStatePtr,
-    ex: Arc<smol::Executor<'_>>,
-) {
-    // Note: when a node can start produce proposals is only enforced in code,
-    // where we verify if the hardware can keep up with the consensus, by
-    // counting how many consecutive slots node successfully listened and process
-    // everything. Additionally, we check each proposer coin creation slot to be
-    // greater than an epoch length. Later, this will be enforced via contract,
-    // where it will be explicit when a node can produce proposals,
-    // and after which slot they can be considered as valid.
-    let mut listened_slots = 0;
-    let mut changed_status = false;
-    loop {
-        // Check if node can start proposing.
-        // This code ensures that we only change the status once
-        // and listened_slots doesn't increment further.
-        if listened_slots > constants::EPOCH_LENGTH {
-            if !changed_status {
-                info!(target: "consensus::proposal", "consensus: Node can start proposing!");
-                state.write().await.consensus.proposing = true;
-                changed_status = true;
-            }
-        } else {
-            listened_slots += 1;
-        }
-
-        // Node waits and execute consensus protocol propose period.
-        if propose_period(consensus_p2p.clone(), state.clone()).await {
-            // Node needs to resync
-            warn!(
-                target: "consensus::proposal",
-                "consensus: Node missed slot {} due to proposal processing, resyncing...",
-                state.read().await.consensus.time_keeper.current_slot()
-            );
-            break
-        }
-
-        // Node waits and execute consensus protocol finalization period.
-        if finalization_period(sync_p2p.clone(), state.clone(), ex.clone()).await {
-            // Node needs to resync
-            warn!(
-                target: "consensus::proposal",
-                "consensus: Node missed slot {} due to finalizated blocks processing, resyncing...",
-                state.read().await.consensus.time_keeper.current_slot()
-            );
-            break
-        }
-    }
-}
-
-/// async function to wait and execute consensus protocol propose period.
-/// Propose period consists of 2 parts:
-///     - Generate current slot
-///     - Check if slot leader to generate and broadcast proposal
-/// Returns flag in case node needs to resync.
-async fn propose_period(consensus_p2p: P2pPtr, state: ValidatorStatePtr) -> bool {
-    // Node sleeps until next slot
-    let seconds_next_slot = state.read().await.consensus.time_keeper.next_n_slot_start(1);
-    info!(target: "consensus::proposal", "consensus: Waiting for next slot ({} sec)", seconds_next_slot);
-    sleep(seconds_next_slot).await;
-
-    // Keep a record of slot to verify if next slot got skipped during processing
-    let processing_slot = state.read().await.consensus.time_keeper.current_slot();
-
-    // Retrieve current forks last and second to last hash
-    let (fork_hashes, fork_previous_hashes) = state.read().await.consensus.fork_hashes();
-
-    // Retrieve slot sigmas
-    let (sigma1, sigma2) = state.write().await.consensus.sigmas();
-    // Node checks if epoch has changed and generate slot
-    let epoch_changed = state
-        .write()
-        .await
-        .consensus
-        .epoch_changed(fork_hashes, fork_previous_hashes, sigma1, sigma2)
-        .await;
-    match epoch_changed {
-        Ok(changed) => {
-            if changed {
-                info!(target: "consensus::proposal", "consensus: New epoch started: {}", state.read().await.consensus.epoch);
-            }
-        }
-        Err(e) => {
-            error!(target: "consensus::proposal", "consensus: Epoch check failed: {}", e);
-            return false
-        }
-    };
-
-    // Node checks if it's the slot leader to generate a new proposal
-    // for that slot.
-    let (won, fork_index, coin_index) =
-        state.write().await.consensus.is_slot_leader(sigma1, sigma2);
-    let result = if won {
-        state.write().await.propose(processing_slot, fork_index, coin_index, sigma1, sigma2).await
-    } else {
-        Ok(None)
-    };
-    let (proposal, coin, derived_blind) = match result {
-        Ok(pair) => {
-            if pair.is_none() {
-                info!(target: "consensus::proposal", "consensus: Node is not the slot lead");
-                return false
-            }
-            pair.unwrap()
-        }
-        Err(e) => {
-            error!(target: "consensus::proposal", "consensus: Block proposal failed: {}", e);
-            return false
-        }
-    };
-
-    // Node checks if it missed finalization period due to proposal creation
-    let next_slot_start = state.read().await.consensus.time_keeper.next_n_slot_start(1);
-    if next_slot_start <= constants::FINAL_SYNC_DUR {
-        warn!(
-            target: "consensus::proposal",
-            "consensus: Node missed slot {} finalization period due to proposal creation, resyncing...",
-            state.read().await.consensus.time_keeper.current_slot()
-        );
-        return true
-    }
-
-    // Node stores the proposal and broadcast to rest nodes
-    info!(target: "consensus::proposal", "consensus: Node is the slot leader: Proposed block: {}", proposal);
-    debug!(target: "consensus::proposal", "consensus: Full proposal: {:?}", proposal);
-    match state
-        .write()
-        .await
-        .receive_proposal(&proposal, Some((coin_index, coin, derived_blind)))
-        .await
-    {
-        Ok(_) => {
-            // Here we don't have to check to broadcast, because the flag
-            // will always be true, since the node is able to produce proposals
-            info!(target: "consensus::proposal", "consensus: Block proposal saved successfully");
-            // Broadcast proposal to other consensus nodes
-            consensus_p2p.broadcast(&proposal).await;
-        }
-        Err(e) => {
-            error!(target: "consensus::proposal", "consensus: Block proposal save failed: {}", e);
-        }
-    }
-
-    // Verify node didn't skip next slot
-    processing_slot != state.read().await.consensus.time_keeper.current_slot()
-}
-
-/// async function to wait and execute consensus protocol finalization period.
-/// Returns flag in case node needs to resync.
-async fn finalization_period(
-    _sync_p2p: P2pPtr,
-    state: ValidatorStatePtr,
-    _ex: Arc<smol::Executor<'_>>,
-) -> bool {
-    // Node sleeps until finalization sync period starts
-    let next_slot_start = state.read().await.consensus.time_keeper.next_n_slot_start(1);
-    if next_slot_start > constants::FINAL_SYNC_DUR {
-        let seconds_sync_period = next_slot_start - constants::FINAL_SYNC_DUR;
-        info!(target: "consensus::proposal", "consensus: Waiting for finalization sync period ({} sec)", seconds_sync_period);
-        sleep(seconds_sync_period).await;
-    } else {
-        warn!(
-            target: "consensus::proposal",
-            "consensus: Node missed slot {} finalization period due to proposals processing, resyncing...",
-            state.read().await.consensus.time_keeper.current_slot()
-        );
-        return true
-    }
-
-    // Keep a record of slot to verify if next slot got skipped during processing
-    let completed_slot = state.read().await.consensus.time_keeper.current_slot();
-
-    // Check if any forks can be finalized
-    /*
-    match state.write().await.chain_finalization().await {
-        Ok((to_broadcast_block, to_broadcast_slots)) => {
-            // Broadcasting in background
-            if !to_broadcast_block.is_empty() || !to_broadcast_slots.is_empty() {
-                ex.spawn(async move {
-                    // Broadcast finalized blocks info, if any:
-                    info!(target: "consensus::proposal", "consensus: Broadcasting finalized blocks");
-                    for info in to_broadcast_block {
-                        sync_p2p.broadcast(&info).await;
-                    }
-
-                    // Broadcast finalized slots, if any:
-                    info!(target: "consensus::proposal", "consensus: Broadcasting finalized slots");
-                    for slot in to_broadcast_slots {
-                        sync_p2p.broadcast(slot).await;
-                        info!(target: "consensus::proposal", "consensus: Broadcasted slot");
-                        // TODO: You can give an error if you query P2P and check if there are any connected channels
-                    }
-                })
-                .detach();
-            } else {
-                info!(target: "consensus::proposal", "consensus: No finalized blocks or slots to broadcast");
-            }
-        }
-        Err(e) => {
-            error!(target: "consensus::proposal", "consensus: Finalization check failed: {}", e);
-        }
-    }
-    */
-    // Verify node didn't skip next slot
-    completed_slot != state.read().await.consensus.time_keeper.current_slot()
-}

+ 0 - 28
src/consensus/tx.rs

@@ -1,28 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
-
-use crate::consensus::{EncryptedTxRcpt, TransferStx};
-
-/// transfer transaction
-#[derive(Debug, Clone, SerialDecodable, SerialEncodable)]
-pub struct Tx {
-    pub xfer: TransferStx,
-    pub cipher: EncryptedTxRcpt,
-}

+ 0 - 118
src/consensus/types.rs

@@ -1,118 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! Type aliases used in the consensus codebase.
-use std::ops::{Add, AddAssign, Div, Mul, Sub};
-
-use dashu::{
-    base::Abs,
-    float::{round::mode::Zero, FBig, Repr},
-};
-
-use super::constants::RADIX_BITS;
-
-const B: u64 = 10;
-
-#[derive(Clone, PartialEq, PartialOrd, Debug)]
-pub struct Float10(FBig<Zero, B>);
-
-impl Float10 {
-    pub fn repr(&self) -> &Repr<B> {
-        self.0.repr()
-    }
-
-    pub fn abs(&self) -> Self {
-        Self(self.0.clone().abs())
-    }
-
-    pub fn powf(&self, exp: Self) -> Self {
-        Self(self.0.powf(&exp.0))
-    }
-
-    pub fn ln(&self) -> Self {
-        Self(self.0.ln())
-    }
-}
-
-impl Add for Float10 {
-    type Output = Self;
-
-    fn add(self, other: Self) -> Self {
-        Self(self.0 + other.0)
-    }
-}
-
-impl AddAssign for Float10 {
-    fn add_assign(&mut self, other: Self) {
-        *self = Self(self.0.clone() + other.0);
-    }
-}
-
-impl Sub for Float10 {
-    type Output = Self;
-
-    fn sub(self, other: Self) -> Self {
-        Self(self.0 - other.0)
-    }
-}
-
-impl Mul for Float10 {
-    type Output = Self;
-
-    fn mul(self, other: Self) -> Self {
-        Self(self.0 * other.0)
-    }
-}
-
-impl Div for Float10 {
-    type Output = Self;
-
-    fn div(self, other: Self) -> Self {
-        Self(self.0 / other.0)
-    }
-}
-
-impl std::fmt::Display for Float10 {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        write!(f, "{}", self.0)
-    }
-}
-
-impl TryFrom<&str> for Float10 {
-    type Error = crate::Error;
-
-    fn try_from(value: &str) -> Result<Self, Self::Error> {
-        Ok(Self(FBig::from_str_native(value)?.with_precision(RADIX_BITS).value()))
-    }
-}
-
-impl TryFrom<u64> for Float10 {
-    type Error = crate::Error;
-
-    fn try_from(value: u64) -> Result<Self, Self::Error> {
-        Ok(Self(FBig::from(value)))
-    }
-}
-
-impl TryFrom<i64> for Float10 {
-    type Error = crate::Error;
-
-    fn try_from(value: i64) -> Result<Self, Self::Error> {
-        Ok(Self(FBig::from(value)))
-    }
-}

+ 0 - 111
src/consensus/utils.rs

@@ -1,111 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::pasta::{group::ff::PrimeField, pallas};
-use dashu::integer::{IBig, Sign, UBig};
-use log::debug;
-
-use super::Float10;
-
-pub fn fbig2ibig(f: Float10) -> IBig {
-    let rad = IBig::from(10);
-    let sig = f.repr().significand();
-    let exp = f.repr().exponent();
-
-    let val: IBig = if exp >= 0 {
-        sig.clone() * rad.pow(exp.unsigned_abs())
-    } else {
-        sig.clone() / rad.pow(exp.unsigned_abs())
-    };
-
-    val
-}
-
-/// note! nagative values in pallas field won't wraps, and won't
-/// convert back to same value.
-pub fn fbig2base(f: Float10) -> pallas::Base {
-    debug!(target: "consensus::utils", "fbig -> base (f): {}", f);
-    let val: IBig = fbig2ibig(f);
-    let (sign, word) = val.as_sign_words();
-    let mut words: [u64; 4] = [0, 0, 0, 0];
-    words[..word.len()].copy_from_slice(word);
-    match sign {
-        Sign::Positive => pallas::Base::from_raw(words),
-        Sign::Negative => pallas::Base::from_raw(words).neg(),
-    }
-}
-
-/// note! only support positive conversion, and zero.
-/// used for testing purpose on non-negative values at the moment.
-pub fn base2ibig(base: pallas::Base) -> IBig {
-    //
-    let byts: [u8; 32] = base.to_repr();
-    let words: [u64; 4] = [
-        u64::from_le_bytes(byts[0..8].try_into().expect("")),
-        u64::from_le_bytes(byts[8..16].try_into().expect("")),
-        u64::from_le_bytes(byts[16..24].try_into().expect("")),
-        u64::from_le_bytes(byts[24..32].try_into().expect("")),
-    ];
-    let uparts = UBig::from_words(&words);
-    IBig::from_parts(Sign::Positive, uparts)
-}
-
-#[cfg(test)]
-mod tests {
-    use dashu::integer::IBig;
-
-    use crate::consensus::{
-        types::Float10,
-        utils::{base2ibig, fbig2base, fbig2ibig},
-    };
-    use darkfi_sdk::pasta::pallas;
-
-    #[test]
-    fn dashu_fbig2ibig() {
-        let f = Float10::try_from("234234223.000").unwrap();
-        let i: IBig = fbig2ibig(f);
-        let sig = IBig::from(234234223);
-        assert_eq!(i, sig);
-    }
-
-    #[test]
-    fn dashu_test_base2ibig() {
-        //
-        let fbig: Float10 = Float10::try_from(
-            "289480223093290488558927462521719769633630564819415607159546767643499676303",
-        )
-        .unwrap();
-        let ibig = fbig2ibig(fbig.clone());
-        let res_base: pallas::Base = fbig2base(fbig.clone());
-        let res_ibig: IBig = base2ibig(res_base);
-        assert_eq!(res_ibig, ibig);
-    }
-
-    #[test]
-    fn dashu_test2_base2ibig() {
-        //assert that field wrapping for negative values won't hold during conversions.
-        let fbig: Float10 = Float10::try_from(
-            "-20065240046497827215558476051577517633529246907153511707181011345840062564.87",
-        )
-        .unwrap();
-        let ibig = fbig2ibig(fbig.clone());
-        let res_base: pallas::Base = fbig2base(fbig.clone());
-        let res_ibig: IBig = base2ibig(res_base);
-        assert_ne!(res_ibig, ibig);
-    }
-}

+ 0 - 1199
src/consensus/validator.rs

@@ -1,1199 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::{collections::HashMap, io::Cursor, sync::Arc};
-
-use darkfi_sdk::{
-    blockchain::Slot,
-    crypto::{
-        contract_id::{CONSENSUS_CONTRACT_ID, DAO_CONTRACT_ID, MONEY_CONTRACT_ID},
-        schnorr::{SchnorrPublic, SchnorrSecret},
-        MerkleNode, MerkleTree, PublicKey, SecretKey,
-    },
-    pasta::{group::ff::PrimeField, pallas},
-};
-use darkfi_serial::{serialize, Decodable, Encodable, WriteExt};
-use halo2_proofs::arithmetic::Field;
-use log::{debug, error, info, warn};
-use rand::rngs::OsRng;
-use smol::lock::RwLock;
-
-use crate::{
-    blockchain::{BlockInfo, Blockchain, BlockchainOverlay, BlockchainOverlayPtr},
-    rpc::jsonrpc::JsonSubscriber,
-    runtime::vm_runtime::Runtime,
-    tx::Transaction,
-    util::time::{TimeKeeper, Timestamp},
-    wallet::WalletPtr,
-    zk::{
-        proof::{ProvingKey, VerifyingKey},
-        vm::ZkCircuit,
-        vm_heap::empty_witnesses,
-    },
-    zkas::ZkBinary,
-    Error, Result,
-};
-
-use super::{
-    constants,
-    lead_coin::LeadCoin,
-    state::{ConsensusState, Fork, StateCheckpoint},
-    BlockProposal, Header, LeadInfo, LeadProof,
-};
-
-/// Atomic pointer to validator state.
-pub type ValidatorStatePtr = Arc<RwLock<ValidatorState>>;
-
-/// This struct represents the state of a validator node.
-pub struct ValidatorState {
-    /// Leader proof proving key
-    pub lead_proving_key: Option<ProvingKey>,
-    /// Leader proof verifying key
-    pub lead_verifying_key: VerifyingKey,
-    /// Hot/Live data used by the consensus algorithm
-    pub consensus: ConsensusState,
-    /// Canonical (finalized) blockchain
-    pub blockchain: Blockchain,
-    /// A map of various subscribers exporting live info from the blockchain
-    pub subscribers: HashMap<&'static str, JsonSubscriber>,
-    /// Wallet interface
-    pub wallet: WalletPtr,
-    /// Flag signalling node has finished initial sync
-    pub synced: bool,
-    /// Flag to enable single-node mode
-    pub single_node: bool,
-}
-
-impl ValidatorState {
-    #[allow(clippy::too_many_arguments)]
-    pub async fn new(
-        db: &sled::Db,
-        bootstrap_ts: Timestamp,
-        genesis_ts: Timestamp,
-        genesis_data: blake3::Hash,
-        initial_distribution: u64,
-        wallet: WalletPtr,
-        faucet_pubkeys: Vec<PublicKey>,
-        enable_participation: bool,
-        single_node: bool,
-    ) -> Result<ValidatorStatePtr> {
-        debug!(target: "consensus::validator", "Initializing ValidatorState");
-
-        debug!(target: "consensus::validator", "Initializing wallet tables for consensus");
-
-        // Initialize consensus coin table.
-        // NOTE: In future this will be redundant as consensus coins will live in the money contract.
-        if enable_participation {
-            wallet.exec_sql(include_str!("consensus_coin.sql")).await?;
-        }
-
-        debug!(target: "consensus::validator", "Generating leader proof keys with k: {}", constants::LEADER_PROOF_K);
-        let bincode = include_bytes!("../../proof/lead.zk.bin");
-        let zkbin = ZkBinary::decode(bincode)?;
-        let circuit = ZkCircuit::new(empty_witnesses(&zkbin)?, &zkbin);
-
-        let lead_verifying_key = VerifyingKey::build(constants::LEADER_PROOF_K, &circuit);
-        // We only need this proving key if we're going to participate in the consensus.
-        let lead_proving_key = if enable_participation {
-            Some(ProvingKey::build(constants::LEADER_PROOF_K, &circuit))
-        } else {
-            None
-        };
-
-        let blockchain = Blockchain::new(db)?;
-        let mut genesis_block = BlockInfo::default();
-        genesis_block.header.timestamp = genesis_ts;
-        blockchain.add_block(&genesis_block)?;
-
-        let consensus = ConsensusState::new(
-            wallet.clone(),
-            blockchain.clone(),
-            bootstrap_ts,
-            genesis_ts,
-            genesis_data,
-            initial_distribution,
-            single_node,
-        );
-
-        // -----NATIVE WASM CONTRACTS-----
-        // This is the current place where native contracts are being deployed.
-        // When the `Blockchain` object is created, it doesn't care whether it
-        // already has the contract data or not. If there's existing data, it
-        // will just open the necessary db and trees, and give back what it has.
-        // This means that on subsequent runs our native contracts will already
-        // be in a deployed state, so what we actually do here is a redeployment.
-        // This kind of operation should only modify the contract's state in case
-        // it wasn't deployed before (meaning the initial run). Otherwise, it
-        // shouldn't touch anything, or just potentially update the db schemas or
-        // whatever is necessary. This logic should be handled in the init function
-        // of the actual contract, so make sure the native contracts handle this well.
-
-        // The faucet pubkeys are pubkeys which are allowed to create clear inputs
-        // in the money contract.
-        let money_contract_deploy_payload = serialize(&faucet_pubkeys);
-        let dao_contract_deploy_payload = vec![];
-        let consensus_contract_deploy_payload = vec![];
-
-        let native_contracts = vec![
-            (
-                "Money Contract",
-                *MONEY_CONTRACT_ID,
-                include_bytes!("../contract/money/darkfi_money_contract.wasm").to_vec(),
-                money_contract_deploy_payload,
-            ),
-            (
-                "DAO Contract",
-                *DAO_CONTRACT_ID,
-                include_bytes!("../contract/dao/darkfi_dao_contract.wasm").to_vec(),
-                dao_contract_deploy_payload,
-            ),
-            (
-                "Consensus Contract",
-                *CONSENSUS_CONTRACT_ID,
-                include_bytes!("../contract/consensus/darkfi_consensus_contract.wasm").to_vec(),
-                consensus_contract_deploy_payload,
-            ),
-        ];
-
-        info!(target: "consensus::validator", "Deploying native wasm contracts");
-        let blockchain_overlay = BlockchainOverlay::new(&blockchain)?;
-        for nc in native_contracts {
-            info!(target: "consensus::validator", "Deploying {} with ContractID {}", nc.0, nc.1);
-            let mut runtime = Runtime::new(
-                &nc.2[..],
-                blockchain_overlay.clone(),
-                nc.1,
-                consensus.time_keeper.clone(),
-            )?;
-            runtime.deploy(&nc.3)?;
-            info!(target: "consensus::validator", "Successfully deployed {}", nc.0);
-        }
-        blockchain_overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
-
-        info!(target: "consensus::validator", "Finished deployment of native wasm contracts");
-        // -----END NATIVE WASM CONTRACTS-----
-
-        // Here we initialize various subscribers that can export live consensus/blockchain data.
-        let mut subscribers = HashMap::new();
-        let block_subscriber = JsonSubscriber::new("blockchain.subscribe_blocks");
-        let err_txs_subscriber = JsonSubscriber::new("blockchain.subscribe_err_txs");
-        subscribers.insert("blocks", block_subscriber);
-        subscribers.insert("err_txs", err_txs_subscriber);
-
-        let state = Arc::new(RwLock::new(ValidatorState {
-            lead_proving_key,
-            lead_verifying_key,
-            consensus,
-            blockchain,
-            subscribers,
-            wallet,
-            synced: false,
-            single_node,
-        }));
-
-        Ok(state)
-    }
-
-    /// The node retrieves a transaction, validates its state transition,
-    /// and appends it to the pending txs store.
-    pub async fn append_tx(&mut self, tx: Transaction) -> bool {
-        let tx_hash = blake3::hash(&serialize(&tx));
-        let tx_in_txstore = match self.blockchain.transactions.contains(&tx_hash) {
-            Ok(v) => v,
-            Err(e) => {
-                error!(target: "consensus::validator", "append_tx(): Failed querying txstore: {}", e);
-                return false
-            }
-        };
-
-        let tx_in_pending_txs_store = match self.blockchain.pending_txs.contains(&tx_hash) {
-            Ok(v) => v,
-            Err(e) => {
-                error!(target: "consensus::validator", "append_tx(): Failed querying pending txs store: {}", e);
-                return false
-            }
-        };
-
-        if tx_in_txstore || tx_in_pending_txs_store {
-            info!(target: "consensus::validator", "append_tx(): We have already seen this tx.");
-            return false
-        }
-
-        info!(target: "consensus::validator", "append_tx(): Starting state transition validation");
-        match self
-            .verify_transactions(&[tx.clone()], self.consensus.time_keeper.current_slot(), false)
-            .await
-        {
-            Ok(erroneous_txs) => {
-                if !erroneous_txs.is_empty() {
-                    error!(target: "consensus::validator", "append_tx(): Erroneous transaction detected");
-                    return false
-                }
-            }
-            Err(e) => {
-                error!(target: "consensus::validator", "append_tx(): Failed to verify transaction: {}", e);
-                return false
-            }
-        }
-
-        if let Err(e) = self.blockchain.add_pending_txs(&[tx]) {
-            error!(target: "consensus::validator", "append_tx(): Failed to insert transaction to pending txs store: {}", e);
-            return false
-        }
-        info!(target: "consensus::validator", "append_tx(): Appended tx to pending txs store");
-        true
-    }
-
-    /// The node retrieves transactions vector, validates their state transition,
-    /// and appends successfull ones to the pending txs store.
-    pub async fn append_pending_txs(&mut self, txs: &[Transaction]) {
-        let mut filtered_txs = vec![];
-        // Filter already seen transactions
-        for tx in txs {
-            let tx_hash = blake3::hash(&serialize(tx));
-            let tx_in_txstore = match self.blockchain.transactions.contains(&tx_hash) {
-                Ok(v) => v,
-                Err(e) => {
-                    error!(target: "consensus::validator", "append_pending_txs(): Failed querying txstore: {}", e);
-                    continue
-                }
-            };
-
-            let tx_in_pending_txs_store = match self.blockchain.pending_txs.contains(&tx_hash) {
-                Ok(v) => v,
-                Err(e) => {
-                    error!(target: "consensus::validator", "append_pending_txs(): Failed querying pending txs store: {}", e);
-                    continue
-                }
-            };
-
-            if tx_in_txstore || tx_in_pending_txs_store {
-                info!(target: "consensus::validator", "append_pending_txs(): We have already seen this tx.");
-                continue
-            }
-
-            filtered_txs.push(tx.clone());
-        }
-
-        // Verify transactions and filter erroneous ones
-        info!(target: "consensus::validator", "append_pending_txs(): Starting state transition validation");
-        let erroneous_txs = match self
-            .verify_transactions(
-                &filtered_txs[..],
-                self.consensus.time_keeper.current_slot(),
-                false,
-            )
-            .await
-        {
-            Ok(erroneous_txs) => erroneous_txs,
-            Err(e) => {
-                error!(target: "consensus::validator", "append_pending_txs(): Failed to verify transactions: {}", e);
-                return
-            }
-        };
-        if !erroneous_txs.is_empty() {
-            filtered_txs.retain(|x| !erroneous_txs.contains(x));
-        }
-
-        if let Err(e) = self.blockchain.add_pending_txs(&filtered_txs) {
-            error!(target: "consensus::validator", "append_pending_txs(): Failed to insert transactions to pending txs store: {}", e);
-            return
-        }
-        info!(target: "consensus::validator", "append_pending_txs(): Appended tx to pending txs store");
-    }
-
-    /// The node removes erroneous transactions from the pending txs store.
-    async fn purge_pending_txs(&self) -> Result<()> {
-        info!(target: "consensus::validator", "purge_pending_txs(): Removing erroneous transactions from pending transactions store...");
-        let pending_txs = self.blockchain.get_pending_txs()?;
-        if pending_txs.is_empty() {
-            info!(target: "consensus::validator", "purge_pending_txs(): No pending transactions found");
-            return Ok(())
-        }
-        let erroneous_txs = self
-            .verify_transactions(&pending_txs[..], self.consensus.time_keeper.current_slot(), false)
-            .await?;
-        if erroneous_txs.is_empty() {
-            info!(target: "consensus::validator", "purge_pending_txs(): No erroneous transactions found");
-            return Ok(())
-        }
-        info!(target: "consensus::validator", "purge_pending_txs(): Removing {} erroneous transactions...", erroneous_txs.len());
-        self.blockchain.remove_pending_txs(&erroneous_txs)?;
-
-        let _err_txs_subscriber = self.subscribers.get("err_txs").unwrap();
-        for err_tx in erroneous_txs {
-            let _tx_hash = blake3::hash(&serialize(&err_tx)).to_hex().as_str().to_string();
-            info!(target: "consensus::validator", "purge_pending_txs(): Sending notification about erroneous transaction");
-            // TODO: err_txs_subscriber.notify(&[tx_hash]).await;
-        }
-
-        Ok(())
-    }
-
-    /// Generate a block proposal for the current slot, containing all
-    /// pending transactions. Proposal extends the longest fork
-    /// chain the node is holding.
-    pub async fn propose(
-        &mut self,
-        slot: u64,
-        fork_index: i64,
-        coin_index: usize,
-        sigma1: pallas::Base,
-        sigma2: pallas::Base,
-    ) -> Result<Option<(BlockProposal, LeadCoin, pallas::Scalar)>> {
-        let eta = self.consensus.get_last_eta();
-        // Check if node can produce proposals
-        if !self.consensus.proposing {
-            return Ok(None)
-        }
-
-        // Generate proposal
-        let mut unproposed_txs = self.unproposed_txs(fork_index)?;
-        // Verify transactions and filter erroneous ones
-        let erroneous_txs = self
-            .verify_transactions(
-                &unproposed_txs[..],
-                self.consensus.time_keeper.current_slot(),
-                false,
-            )
-            .await?;
-        if !erroneous_txs.is_empty() {
-            unproposed_txs.retain(|x| !erroneous_txs.contains(x));
-        }
-        let mut tree = MerkleTree::new(100);
-        // The following is pretty weird, so something better should be done.
-        for tx in &unproposed_txs {
-            let mut hash = [0_u8; 32];
-            hash[0..31].copy_from_slice(&blake3::hash(&serialize(tx)).as_bytes()[0..31]);
-            tree.append(MerkleNode::from(pallas::Base::from_repr(hash).unwrap()));
-        }
-        let root = tree.root(0).unwrap();
-
-        // Checking if extending a fork or canonical
-        let (prev_hash, coin) = if fork_index == -1 {
-            (self.blockchain.last()?.1, self.consensus.coins[coin_index].clone())
-        } else {
-            let checkpoint = self.consensus.forks[fork_index as usize].sequence.last().unwrap();
-            (checkpoint.proposal.hash, checkpoint.coins[coin_index].clone())
-        };
-
-        // Generate derived coin blind
-        let derived_blind = pallas::Scalar::random(&mut OsRng);
-
-        // Generating leader proof
-        let (proof, public_inputs) = coin.create_lead_proof(
-            sigma1,
-            sigma2,
-            eta,
-            pallas::Base::from(self.consensus.time_keeper.current_slot()),
-            self.lead_proving_key.as_ref().unwrap(),
-            derived_blind,
-        );
-
-        // Signing using coin
-        let secret_key = coin.coin1_sk;
-        let header = Header::new(
-            prev_hash,
-            self.consensus.time_keeper.slot_epoch(slot),
-            slot,
-            Timestamp::current_time(),
-            root,
-        );
-        let signed_proposal =
-            SecretKey::from(secret_key).sign(&mut OsRng, &header.headerhash().as_bytes()[..]);
-        let public_key = PublicKey::from_secret(secret_key.into());
-
-        let lead_info = LeadInfo::new(
-            signed_proposal,
-            public_key,
-            public_inputs,
-            coin.slot,
-            eta,
-            LeadProof::from(proof?),
-            self.consensus.previous_leaders,
-        );
-
-        Ok(Some((BlockProposal::new(header, unproposed_txs, lead_info), coin, derived_blind)))
-    }
-
-    /// Retrieve all pending transactions not proposed in previous blocks
-    /// of provided index chain.
-    pub fn unproposed_txs(&self, index: i64) -> Result<Vec<Transaction>> {
-        let unproposed_txs = if index == -1 {
-            // If index is -1 (canonical blockchain) a new fork will be generated,
-            // therefore all unproposed transactions can be included in the proposal.
-            self.blockchain.get_pending_txs()?
-        } else {
-            // We iterate over the fork chain proposals to find already proposed
-            // transactions and remove them from the local unproposed_txs vector.
-            let mut filtered_txs = self.blockchain.get_pending_txs()?;
-            let chain = &self.consensus.forks[index as usize];
-            for state_checkpoint in &chain.sequence {
-                for tx in &state_checkpoint.proposal.block.txs {
-                    if let Some(pos) = filtered_txs.iter().position(|txs| *txs == *tx) {
-                        filtered_txs.remove(pos);
-                    }
-                }
-            }
-            filtered_txs
-        };
-
-        // Check if transactions exceed configured cap
-        let cap = constants::TXS_CAP;
-        if unproposed_txs.len() > cap {
-            return Ok(unproposed_txs[0..cap].to_vec())
-        }
-
-        Ok(unproposed_txs)
-    }
-
-    /// Given a proposal, the node verify its sender (slot leader) and finds which blockchain
-    /// it extends. If the proposal extends the canonical blockchain, a new fork chain is created.
-    /// Returns flag to signal if proposal should be broadcasted. Only active consensus participants
-    /// should broadcast proposals.
-    pub async fn receive_proposal(
-        &mut self,
-        proposal: &BlockProposal,
-        coin: Option<(usize, LeadCoin, pallas::Scalar)>,
-    ) -> Result<bool> {
-        let current = self.consensus.time_keeper.current_slot();
-        // Node hasn't started participating
-        match self.consensus.participating {
-            Some(start) => {
-                if current < start {
-                    return Ok(false)
-                }
-            }
-            None => return Ok(false),
-        }
-
-        // Node have already checked for finalization in this slot
-        if current <= self.consensus.checked_finalization {
-            warn!(target: "consensus::validator", "receive_proposal(): Proposal received after finalization sync period.");
-            return Err(Error::ProposalAfterFinalizationError)
-        }
-
-        // Proposal validations
-        let lf = &proposal.block.lead_info;
-        let hdr = &proposal.block.header;
-
-        // Ignore proposal if not for current slot
-        if hdr.slot != current {
-            return Err(Error::ProposalNotForCurrentSlotError)
-        }
-
-        // Verify that proposer can produce proposals.
-        // Nodes that created coins in the bootstrap slot can propose immediately.
-        // NOTE: Later, this will be enforced via contract, where it will be explicit
-        // when a node can produce proposals, and after which slot they can be considered as valid.
-        let elapsed_slots = current - lf.coin_slot;
-        if lf.coin_slot != self.consensus.bootstrap_slot &&
-            elapsed_slots <= (constants::EPOCH_LENGTH as u64)
-        {
-            warn!(
-                target: "consensus::validator",
-                "receive_proposal(): Proposer {} is not eligible to produce proposals",
-                lf.public_key
-            );
-            return Err(Error::ProposalProposerNotEligible)
-        }
-
-        // Check if proposal extends any existing fork chains
-        let index = self.consensus.find_extended_chain_index(proposal)?;
-        if index == -2 {
-            return Err(Error::ExtendedChainIndexNotFound)
-        }
-
-        // Check that proposal transactions don't exceed limit
-        if proposal.block.txs.len() > constants::TXS_CAP {
-            warn!(
-                target: "consensus::validator",
-                "receive_proposal(): Received proposal transactions exceed configured cap: {} - {}",
-                proposal.block.txs.len(),
-                constants::TXS_CAP
-            );
-            return Err(Error::ProposalTxsExceedCapError)
-        }
-
-        // Verify proposal signature is valid based on producer public key
-        // TODO: derive public key from proof
-        if !lf.public_key.verify(proposal.header.as_bytes(), &lf.signature) {
-            warn!(target: "consensus::validator", "receive_proposal(): Proposer {} signature could not be verified", lf.public_key);
-            return Err(Error::InvalidSignature)
-        }
-
-        // Check if proposal hash matches actual one
-        let proposal_hash = proposal.block.blockhash();
-        if proposal.hash != proposal_hash {
-            warn!(
-                target: "consensus::validator",
-                "receive_proposal(): Received proposal contains mismatched hashes: {} - {}",
-                proposal.hash, proposal_hash
-            );
-            return Err(Error::ProposalHashesMissmatchError)
-        }
-
-        // Check if proposal header matches actual one
-        let proposal_header = hdr.headerhash();
-        if proposal.header != proposal_header {
-            warn!(
-                target: "consensus::validator",
-                "receive_proposal(): Received proposal contains mismatched headers: {} - {}",
-                proposal.header, proposal_header
-            );
-            return Err(Error::ProposalHeadersMissmatchError)
-        }
-
-        // Ignore node coin validations if we oporate in single-node mode
-        if !self.single_node {
-            // Verify proposal leader proof
-            if let Err(e) = lf.proof.verify(&self.lead_verifying_key, &lf.public_inputs) {
-                error!(target: "consensus::validator", "receive_proposal(): Error during leader proof verification: {}", e);
-                return Err(Error::LeaderProofVerification)
-            };
-            info!(target: "consensus::validator", "receive_proposal(): Leader proof verified successfully!");
-
-            // Validate proposal public value against coin creation slot
-            let (mu_y, mu_rho) = LeadCoin::election_seeds_u64(
-                self.consensus.get_last_eta(),
-                self.consensus.time_keeper.current_slot(),
-            );
-            // y
-            let prop_mu_y = lf.public_inputs[constants::PI_MU_Y_INDEX];
-
-            if mu_y != prop_mu_y {
-                error!(
-                    target: "consensus::validator",
-                    "receive_proposal(): Failed to verify mu_y: {:?}, proposed: {:?}",
-                    mu_y, prop_mu_y
-                );
-                return Err(Error::ProposalPublicValuesMismatched)
-            }
-
-            // rho
-            let prop_mu_rho = lf.public_inputs[constants::PI_MU_RHO_INDEX];
-
-            if mu_rho != prop_mu_rho {
-                error!(
-                    target: "consensus::validator",
-                    "receive_proposal(): Failed to verify mu_rho: {:?}, proposed: {:?}",
-                    mu_rho, prop_mu_rho
-                );
-                return Err(Error::ProposalPublicValuesMismatched)
-            }
-
-            // Validate proposal coin sigmas against current slot
-            let slot = self.consensus.get_slot(current)?;
-            // sigma1
-            let prop_sigma1 = lf.public_inputs[constants::PI_SIGMA1_INDEX];
-            if slot.pid.sigma1 != prop_sigma1 {
-                error!(
-                    target: "consensus::validator",
-                    "receive_proposal(): Failed to verify public value sigma1: {:?}, to proposed: {:?}",
-                    slot.pid.sigma1, prop_sigma1
-                );
-            }
-            // sigma2
-            let prop_sigma2 = lf.public_inputs[constants::PI_SIGMA2_INDEX];
-            if slot.pid.sigma2 != prop_sigma2 {
-                error!(
-                    target: "consensus::validator",
-                    "receive_proposal(): Failed to verify public value sigma2: {:?}, to proposed: {:?}",
-                    slot.pid.sigma2, prop_sigma2
-                );
-            }
-        }
-
-        // Create corresponding state checkpoint for validations
-        let mut state_checkpoint = match index {
-            -1 => {
-                // Extends canonical
-                StateCheckpoint::new(
-                    proposal.clone(),
-                    self.consensus.coins.clone(),
-                    self.consensus.coins_tree.clone(),
-                    self.consensus.nullifiers.clone(),
-                )
-            }
-            _ => {
-                // Extends a fork
-                let previous = self.consensus.forks[index as usize].sequence.last().unwrap();
-                StateCheckpoint::new(
-                    proposal.clone(),
-                    previous.coins.clone(),
-                    previous.coins_tree.clone(),
-                    previous.nullifiers.clone(),
-                )
-            }
-        };
-
-        // Check if proposal coin nullifiers already exist in the state checkpoint
-        let prop_sn = lf.public_inputs[constants::PI_NULLIFIER_INDEX];
-        for sn in &state_checkpoint.nullifiers {
-            if *sn == prop_sn {
-                error!(target: "consensus::validator", "receive_proposal(): Proposal nullifiers exist.");
-                return Err(Error::ProposalIsSpent)
-            }
-        }
-
-        // Validate state transition against canonical state
-        // TODO: This should be validated against fork state
-        info!(target: "consensus::validator", "receive_proposal(): Starting state transition validation");
-        match self.verify_transactions(&proposal.block.txs, current, false).await {
-            Ok(erroneous_txs) => {
-                if !erroneous_txs.is_empty() {
-                    error!(target: "consensus::validator", "Proposal contains erroneous transactions");
-                    return Err(Error::ErroneousTxsDetected)
-                }
-            }
-            Err(e) => {
-                error!(target: "consensus::validator", "receive_proposal(): Transaction verifications failed: {}", e);
-                return Err(e)
-            }
-        }
-
-        // TODO: [PLACEHOLDER] Add rewards validation
-
-        // If proposal came fromself, we derive new coin
-        if let Some((idx, c, derived_blind)) = coin {
-            info!(target: "consensus::validator", "receive_proposal(): Storing derived coin...");
-            // Derive coin
-            let derived = c.derive_coin(&mut state_checkpoint.coins_tree, derived_blind);
-            // Update consensus coin in wallet
-            // NOTE: In future this will be redundant as consensus coins will live in the money contract.
-            let query_str = format!(
-                "UPDATE {} SET {} = ?1",
-                constants::CONSENSUS_COIN_TABLE,
-                constants::CONSENSUS_COIN_COL
-            );
-            let wallet_conn = self.wallet.conn.lock().await;
-            let mut stmt = wallet_conn.prepare(&query_str)?;
-            stmt.execute([serialize(&derived)])?;
-            stmt.finalize()?;
-
-            state_checkpoint.coins[idx] = derived;
-        }
-        // Store proposal coins nullifiers
-        state_checkpoint.nullifiers.push(prop_sn);
-
-        // Extend corresponding chain
-        match index {
-            -1 => {
-                let fork = Fork::new(self.consensus.genesis_block, state_checkpoint);
-                self.consensus.forks.push(fork);
-            }
-            _ => {
-                self.consensus.forks[index as usize].add(&state_checkpoint);
-            }
-        };
-
-        // Increase slot leaders count
-        self.consensus.previous_leaders += 1;
-
-        Ok(true)
-    }
-
-    /// Node checks if any of the fork chains can be finalized.
-    /// Consensus finalization logic:
-    /// - If the node has observed the creation of a fork chain and no other forks exists at same or greater height,
-    ///   it finalizes (appends to canonical blockchain) all proposals in that fork chain.
-    /// When fork chain proposals are finalized, the rest of fork chains are removed and all
-    /// slots are apppended to canonical state.
-    pub async fn chain_finalization(&mut self) -> Result<(Vec<BlockInfo>, Vec<Slot>)> {
-        let slot = self.consensus.time_keeper.current_slot();
-        info!(target: "consensus::validator", "chain_finalization(): Started finalization check for slot: {}", slot);
-        // Set last slot finalization check occured to current slot
-        self.consensus.checked_finalization = slot;
-
-        // First we find longest fork without any other forks at same height
-        let mut fork_index = -1;
-        let mut max_length = 0;
-        for (index, fork) in self.consensus.forks.iter().enumerate() {
-            let length = fork.sequence.len();
-            // Check if less than max
-            if length < max_length {
-                continue
-            }
-            // Check if same length as max
-            if length == max_length {
-                // Setting fork_index so we know we have multiple
-                // forks at same length.
-                fork_index = -2;
-                continue
-            }
-            // Set fork as max
-            fork_index = index as i64;
-            max_length = length;
-        }
-
-        // Check if we found any fork to finalize
-        match fork_index {
-            -2 => {
-                info!(target: "consensus::validator", "chain_finalization(): Eligible forks with same height exist, nothing to finalize.");
-                return Ok((vec![], vec![]))
-            }
-            -1 => {
-                info!(target: "consensus::validator", "chain_finalization(): Nothing to finalize.");
-            }
-            _ => {
-                info!(target: "consensus::validator", "chain_finalization(): Chain {} can be finalized!", fork_index)
-            }
-        }
-
-        if max_length == 0 {
-            return Ok((vec![], vec![]))
-        }
-
-        // Starting finalization
-        let fork = self.consensus.forks[fork_index as usize].clone();
-
-        // Retrieving proposals to finalize
-        let finalized: Vec<BlockInfo> = vec![];
-        for _state_checkpoint in &fork.sequence {
-            //finalized.push(state_checkpoint.proposal.clone().into());
-        }
-
-        // Adding finalized proposals to canonical
-        info!(target: "consensus::validator", "consensus: Adding {} finalized block to canonical chain.", finalized.len());
-        /*
-        match self.blockchain.add(&finalized) {
-            Ok(v) => v,
-            Err(e) => {
-                error!(target: "consensus::validator", "consensus: Failed appending finalized blocks to canonical chain: {}", e);
-                return Err(e)
-            }
-        };
-        */
-
-        let _blocks_subscriber = self.subscribers.get("blocks").unwrap().clone();
-
-        // Validating state transitions
-        for proposal in &finalized {
-            // TODO: Is this the right place? We're already doing this in protocol_sync.
-            // TODO: These state transitions have already been checked. (I wrote this, but where?)
-            // TODO: FIXME: The state transitions have already been written, they have to be in memory
-            //              until this point.
-            info!(target: "consensus::validator", "Applying state transition for finalized block");
-            match self.verify_transactions(&proposal.txs, proposal.header.height, true).await {
-                Ok(erroneous_txs) => {
-                    if !erroneous_txs.is_empty() {
-                        error!(target: "consensus::validator", "Finalized block contains erroneous transactions");
-                        return Err(Error::ErroneousTxsDetected)
-                    }
-                }
-                Err(e) => {
-                    error!(target: "consensus::validator", "Finalized block transaction verifications failed: {}", e);
-                    return Err(e)
-                }
-            }
-
-            // Remove proposal transactions from pending txs store
-            if let Err(e) = self.blockchain.remove_pending_txs(&proposal.txs) {
-                error!(target: "consensus::validator", "Removing finalized block transactions failed: {}", e);
-                return Err(e)
-            }
-
-            info!(target: "consensus::validator", "consensus: Sending notification about finalized block");
-            // TODO: blocks_subscriber.notify(&[proposal.clone()]).await;
-        }
-
-        // Setting leaders history to last proposal leaders count
-        let last_state_checkpoint = fork.sequence.last().unwrap().clone();
-
-        // Setting canonical states from last finalized checkpoint
-        self.consensus.coins = last_state_checkpoint.coins;
-        self.consensus.coins_tree = last_state_checkpoint.coins_tree;
-        self.consensus.nullifiers = last_state_checkpoint.nullifiers;
-
-        // Adding finalized slots to canonical
-        let finalized_slots: Vec<Slot> = self.consensus.slots.clone();
-
-        debug!(
-            target: "consensus::validator",
-            "consensus: Adding {} finalized slots to canonical chain.",
-            finalized_slots.len()
-        );
-        /*
-        match self.blockchain.add_slots(&finalized_slots) {
-            Ok(v) => v,
-            Err(e) => {
-                error!(
-                    target: "consensus::validator",
-                    "consensus: Failed appending finalized slots to canonical chain: {}",
-                    e
-                );
-                return Err(e)
-            }
-        };
-        */
-        // Resetting forks and slots
-        self.consensus.forks = vec![];
-        self.consensus.slots = vec![];
-
-        // Purge pending erroneous txs since canonical state has been changed
-        if let Err(e) = self.purge_pending_txs().await {
-            error!(target: "consensus::validator", "consensus: Purging pending transactions failed: {}", e);
-        }
-
-        Ok((finalized, finalized_slots))
-    }
-
-    // ==========================
-    // State transition functions
-    // ==========================
-    // TODO TESTNET: Write down all cases below
-    // State transition checks should be happening in the following cases for a sync node:
-    // 1) When a finalized block is received
-    // 2) When a transaction is being broadcasted to us
-    // State transition checks should be happening in the following cases for a consensus participating node:
-    // 1) When a finalized block is received
-    // 2) When a transaction is being broadcasted to us
-    // ==========================
-
-    /// Validate and append to canonical state received blocks.
-    async fn receive_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
-        // Verify state transitions for all blocks and their respective transactions.
-        info!(target: "consensus::validator", "receive_blocks(): Starting state transition validations");
-
-        for block in blocks {
-            match self.verify_transactions(&block.txs, block.header.height, true).await {
-                Ok(erroneous_txs) => {
-                    if !erroneous_txs.is_empty() {
-                        error!(target: "consensus::validator", "receive_blocks(): Block contains erroneous transactions");
-                        return Err(Error::ErroneousTxsDetected)
-                    }
-                }
-                Err(e) => {
-                    error!(target: "consensus::validator", "receive_blocks(): Transaction verifications failed: {}", e);
-                    return Err(e)
-                }
-            }
-        }
-
-        info!(target: "consensus::validator", "receive_blocks(): All state transitions passed. Appending blocks to ledger.");
-        //self.blockchain.add(blocks)?;
-
-        Ok(())
-    }
-
-    /// Validate and append to canonical state received finalized block.
-    /// Returns boolean flag indicating already existing block.
-    pub async fn receive_finalized_block(&mut self, block: BlockInfo) -> Result<bool> {
-        if block.header.height > self.consensus.time_keeper.current_slot() {
-            warn!(target: "consensus::validator", "receive_finalized_block(): Ignoring future block: {}", block.header.height);
-            return Ok(false)
-        }
-        match self.blockchain.has_block(&block) {
-            Ok(v) => {
-                if v {
-                    info!(target: "consensus::validator", "receive_finalized_block(): Existing block received");
-                    return Ok(false)
-                }
-            }
-            Err(e) => {
-                error!(target: "consensus::validator", "receive_finalized_block(): failed checking for has_block(): {}", e);
-                return Ok(false)
-            }
-        };
-
-        info!(target: "consensus::validator", "receive_finalized_block(): Executing state transitions");
-        self.receive_blocks(&[block.clone()]).await?;
-
-        let _blocks_subscriber = self.subscribers.get("blocks").unwrap();
-        info!(target: "consensus::validator", "consensus: Sending notification about finalized block");
-        // TODO: blocks_subscriber.notify(&[block.clone()]).await;
-
-        info!(target: "consensus::validator", "receive_finalized_block(): Removing block transactions from pending txs store");
-        self.blockchain.remove_pending_txs(&block.txs)?;
-
-        // Purge pending erroneous txs since canonical state has been changed
-        if let Err(e) = self.purge_pending_txs().await {
-            error!(target: "consensus::validator", "receive_finalized_block(): Purging pending transactions failed: {}", e);
-        }
-
-        Ok(true)
-    }
-
-    /// Validate and append to canonical state received finalized blocks from block sync task.
-    /// Already existing blocks are ignored.
-    pub async fn receive_sync_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
-        let mut new_blocks = vec![];
-        for block in blocks {
-            if block.header.height > self.consensus.time_keeper.current_slot() {
-                warn!(target: "consensus::validator", "receive_sync_blocks(): Ignoring future block: {}", block.header.height);
-                continue
-            }
-            match self.blockchain.has_block(block) {
-                Ok(v) => {
-                    if v {
-                        info!(target: "consensus::validator", "receive_sync_blocks(): Existing block received");
-                        continue
-                    }
-                    new_blocks.push(block.clone());
-                }
-                Err(e) => {
-                    error!(target: "consensus::validator", "receive_sync_blocks(): failed checking for has_block(): {}", e);
-                    continue
-                }
-            };
-        }
-
-        if new_blocks.is_empty() {
-            info!(target: "consensus::validator", "receive_sync_blocks(): no new blocks to append");
-            return Ok(())
-        }
-
-        info!(target: "consensus::validator", "receive_sync_blocks(): Executing state transitions");
-        self.receive_blocks(&new_blocks[..]).await?;
-
-        let _blocks_subscriber = self.subscribers.get("blocks").unwrap();
-        for _block in new_blocks {
-            info!(target: "consensus::validator", "consensus: Sending notification about finalized block");
-            // TODO: blocks_subscriber.notify(&[block]).await;
-        }
-
-        Ok(())
-    }
-
-    /// Validate signatures, wasm execution, and zk proofs for given transaction in
-    /// provided runtimes. If all of those succeed, try to execute a state update
-    /// for the contract calls.
-    async fn verify_transaction(
-        &self,
-        overlay: &BlockchainOverlayPtr,
-        tx: &Transaction,
-        verifying_slot: u64,
-    ) -> Result<()> {
-        let mut runtimes = HashMap::new();
-        let tx_hash = blake3::hash(&serialize(tx));
-        info!(target: "consensus::validator", "Verifying transaction {}", tx_hash);
-
-        // Table of public inputs used for ZK proof verification
-        let mut zkp_table = vec![];
-        // Table of public keys used for signature verification
-        let mut sig_table = vec![];
-        // State updates produced by contract execution
-        let mut updates = vec![];
-        // Map of zk proof verifying keys for the current transaction
-        let mut verifying_keys: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
-
-        // Initialize the map
-        for call in tx.calls.iter() {
-            verifying_keys.insert(call.contract_id.to_bytes(), HashMap::new());
-        }
-
-        // Generate a time keeper using transaction verifying slot
-        let time_keeper = TimeKeeper::new(
-            self.consensus.time_keeper.genesis_ts,
-            self.consensus.time_keeper.epoch_length,
-            self.consensus.time_keeper.slot_time,
-            verifying_slot,
-        );
-
-        // Iterate over all calls to get the metadata
-        for (idx, call) in tx.calls.iter().enumerate() {
-            info!(target: "consensus::validator", "Executing contract call {}", idx);
-
-            // Write the actual payload data
-            let mut payload = vec![];
-            payload.write_u32(idx as u32)?; // Call index
-            tx.calls.encode(&mut payload)?; // Actual call data
-
-            // Instantiate the wasm runtime
-            let runtime_key = call.contract_id.to_string();
-            if !runtimes.contains_key(&runtime_key) {
-                let wasm = self.blockchain.wasm_bincode.get(call.contract_id)?;
-                let r =
-                    Runtime::new(&wasm, overlay.clone(), call.contract_id, time_keeper.clone())?;
-                runtimes.insert(runtime_key.clone(), r);
-            }
-            let runtime = runtimes.get_mut(&runtime_key).unwrap();
-
-            info!(target: "consensus::validator", "Executing \"metadata\" call");
-            let metadata = runtime.metadata(&payload)?;
-
-            // Decode the metadata retrieved from the execution
-            let mut decoder = Cursor::new(&metadata);
-
-            // The tuple is (zkas_ns, public_inputs)
-            let zkp_pub: Vec<(String, Vec<pallas::Base>)> = Decodable::decode(&mut decoder)?;
-
-            let sig_pub: Vec<PublicKey> = Decodable::decode(&mut decoder)?;
-            // TODO: Make sure we've read all the bytes above.
-            info!(target: "consensus::validator", "Successfully executed \"metadata\" call");
-
-            // Here we'll look up verifying keys and insert them into the per-contract map.
-            info!(target: "consensus::validator", "Performing VerifyingKey lookups from the sled db");
-            for (zkas_ns, _) in &zkp_pub {
-                let inner_vk_map = verifying_keys.get_mut(&call.contract_id.to_bytes()).unwrap();
-
-                if inner_vk_map.contains_key(zkas_ns.as_str()) {
-                    continue
-                }
-
-                let (_, vk) = self.blockchain.contracts.get_zkas(
-                    &self.blockchain.sled_db,
-                    &call.contract_id,
-                    zkas_ns,
-                )?;
-
-                inner_vk_map.insert(zkas_ns.to_string(), vk);
-            }
-
-            zkp_table.push(zkp_pub);
-            sig_table.push(sig_pub);
-
-            // After getting the metadata, we run the "exec" function with the same
-            // runtime and the same payload.
-            info!(target: "consensus::validator", "Executing \"exec\" call");
-            let state_update = runtime.exec(&payload)?;
-
-            info!(target: "consensus::validator", "Successfully executed \"exec\" call");
-            updates.push(state_update);
-
-            // At this point we're done with the call and move on to the next one.
-        }
-
-        // When we're done looping and executing over the tx's contract calls, we
-        // move on with verification. First we verify the signatures as that's
-        // cheaper, and then finally we verify the ZK proofs.
-        info!(target: "consensus::validator", "Verifying signatures for transaction {}", tx_hash);
-        if sig_table.len() != tx.signatures.len() {
-            error!(target: "consensus::validator", "Incorrect number of signatures in tx {}", tx_hash);
-            return Err(Error::InvalidSignature)
-        }
-
-        match tx.verify_sigs(sig_table) {
-            Ok(()) => {
-                info!(target: "consensus::validator", "Signatures verification for tx {} successful", tx_hash)
-            }
-            Err(e) => {
-                error!(target: "consensus::validator", "Signature verification for tx {} failed: {}", tx_hash, e);
-                return Err(e)
-            }
-        };
-
-        info!(target: "consensus::validator", "Verifying ZK proofs for transaction {}", tx_hash);
-        match tx.verify_zkps(&verifying_keys, zkp_table).await {
-            Ok(()) => {
-                info!(target: "consensus::validator", "ZK proof verification for tx {} successful", tx_hash)
-            }
-            Err(e) => {
-                error!(target: "consensus::validator", "ZK proof verification for tx {} failed: {}", tx_hash, e);
-                return Err(e)
-            }
-        };
-
-        // After the verifications stage passes we can apply the state updates.
-        assert!(tx.calls.len() == updates.len());
-
-        info!(target: "consensus::validator", "Performing state updates");
-        for (call, update) in tx.calls.iter().zip(updates.iter()) {
-            // Retrieve already initiated runtime and apply update
-            // TODO: Sum up the gas costs of previous calls during execution
-            //       and verification and these.
-            let runtime = runtimes.get_mut(&call.contract_id.to_string()).unwrap();
-            info!(target: "consensus::validator", "Executing \"apply\" call");
-            runtime.apply(update)?;
-            info!(target: "consensus::validator", "State update applied successfully")
-        }
-
-        info!(target: "consensus::validator", "Transaction {} verified successfully", tx_hash);
-
-        Ok(())
-    }
-
-    /// Validate a set of [`Transaction`] in sequence and apply them if all are valid.
-    /// Erroneous transactions are filtered out of the set and returned to caller.
-    /// The function takes a boolean called `write` which tells it to actually write
-    /// the state transitions to the database.
-    pub async fn verify_transactions(
-        &self,
-        txs: &[Transaction],
-        verifying_slot: u64,
-        write: bool,
-    ) -> Result<Vec<Transaction>> {
-        info!(target: "consensus::validator", "Verifying {} transaction(s)", txs.len());
-
-        let mut erroneous_txs = vec![];
-        let overlay = BlockchainOverlay::new(&self.blockchain)?;
-
-        for tx in txs {
-            if let Err(e) = self.verify_transaction(&overlay, tx, verifying_slot).await {
-                warn!(target: "consensus::validator", "Transaction verification failed: {}", e);
-                erroneous_txs.push(tx.clone());
-            }
-        }
-
-        let lock = overlay.lock().unwrap();
-        let mut overlay = lock.overlay.lock().unwrap();
-        if !erroneous_txs.is_empty() {
-            warn!(target: "consensus::validator", "Erroneous transactions found in set");
-            overlay.purge_new_trees()?;
-            return Ok(erroneous_txs)
-        }
-
-        if !write {
-            info!(target: "consensus::validator", "Skipping apply of state updates because write=false");
-            overlay.purge_new_trees()?;
-            return Ok(erroneous_txs)
-        }
-
-        overlay.apply()?;
-
-        Ok(erroneous_txs)
-    }
-
-    /// Append to canonical state received finalized slots from block sync task.
-    pub async fn receive_slots(&mut self, slots: &[Slot]) -> Result<()> {
-        info!(target: "consensus::validator", "receive_slots(): Appending slots to ledger");
-        let mut filtered = vec![];
-        for slot in slots {
-            if slot.id > self.consensus.time_keeper.current_slot() {
-                warn!(target: "consensus::validator", "receive_slots(): Ignoring future slot: {}", slot.id);
-                continue
-            }
-            filtered.push(slot.clone());
-        }
-        //self.blockchain.add_slots(&filtered[..])?;
-
-        Ok(())
-    }
-
-    /// Validate and append to canonical state received finalized slot.
-    /// Returns boolean flag indicating already existing slot.
-    pub async fn receive_finalized_slots(&mut self, slot: Slot) -> Result<bool> {
-        match self.blockchain.has_slot(&slot) {
-            Ok(v) => {
-                if v {
-                    info!(
-                        target: "consensus::validator",
-                        "receive_finalized_slots(): Existing slot received"
-                    );
-                    return Ok(false)
-                }
-            }
-            Err(e) => {
-                error!(target: "consensus::validator", "receive_finalized_slots(): failed checking for has_slot(): {}", e);
-                return Ok(false)
-            }
-        };
-        self.receive_slots(&[slot]).await?;
-        Ok(true)
-    }
-}

+ 0 - 56
src/consensus/wallet.rs

@@ -1,56 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use async_trait::async_trait;
-use darkfi_sdk::crypto::{Keypair, PublicKey, SecretKey};
-use darkfi_serial::deserialize;
-use log::debug;
-
-use crate::{wallet::WalletDb, Result};
-
-const CONSENSUS_KEYS_TABLE: &str = "consensus_keys";
-const CONSENSUS_KEYS_COLUMN_IS_DEFAULT: &str = "is_default";
-
-#[async_trait]
-pub trait ConsensusWallet {
-    async fn get_default_keypair(&self) -> Result<Keypair>;
-}
-
-#[async_trait]
-impl ConsensusWallet for WalletDb {
-    async fn get_default_keypair(&self) -> Result<Keypair> {
-        debug!(target: "consensus::wallet", "Returning default keypair");
-
-        let wallet_conn = self.conn.lock().await;
-        let mut stmt = wallet_conn.prepare(&format!(
-            "SELECT * FROM {} WHERE {} = 1",
-            CONSENSUS_KEYS_TABLE, CONSENSUS_KEYS_COLUMN_IS_DEFAULT
-        ))?;
-
-        let (public, secret): (PublicKey, SecretKey) = stmt.query_row((), |row| {
-            let p_bytes: Vec<u8> = row.get("public")?;
-            let s_bytes: Vec<u8> = row.get("secret")?;
-            let public = deserialize(&p_bytes).unwrap();
-            let secret = deserialize(&s_bytes).unwrap();
-            Ok((public, secret))
-        })?;
-        stmt.finalize()?;
-
-        Ok(Keypair { secret, public })
-    }
-}

+ 0 - 54
src/contract/consensus/Cargo.toml

@@ -1,54 +0,0 @@
-[package]
-name = "darkfi_consensus_contract"
-version = "0.4.1"
-authors = ["Dyne.org foundation <foundation@dyne.org>"]
-license = "AGPL-3.0-only"
-edition = "2021"
-
-[lib]
-crate-type = ["cdylib", "rlib"]
-
-[dependencies]
-blake3 = "1.5.0"
-darkfi-sdk = { path = "../../sdk" }
-darkfi-serial = { path = "../../serial", features = ["derive", "crypto"] }
-darkfi_money_contract = { path = "../money", features = ["no-entrypoint"] }
-thiserror = "1.0.56"
-
-# The following dependencies are used for the client API and
-# probably shouldn't be in WASM
-chacha20poly1305 = { version = "0.10.1", optional = true }
-darkfi = { path = "../../../", features = ["zk", "rpc", "blockchain"], optional = true }
-halo2_proofs = { version = "0.3.0", optional = true }
-log = { version = "0.4.20", optional = true }
-rand = { version = "0.8.5", optional = true }
-
-# These are used just for the integration tests
-[dev-dependencies]
-smol = "1.3.0"
-bs58 = "0.5.0"
-darkfi = {path = "../../../", features = ["tx", "blockchain"]}
-darkfi_money_contract = { path = "../money", features = ["client", "no-entrypoint"] }
-darkfi-contract-test-harness = {path = "../test-harness"}
-simplelog = "0.12.1"
-sled = "0.34.7"
-
-# We need to disable random using "custom" which makes the crate a noop
-# so the wasm32-unknown-unknown target is enabled.
-[target.'cfg(target_arch = "wasm32")'.dependencies]
-getrandom = { version = "0.2.8", features = ["custom"] }
-
-[features]
-default = []
-no-entrypoint = []
-client = [
-    "darkfi",
-    "darkfi-serial/async",
-    "darkfi_money_contract/client",
-    "darkfi_money_contract/no-entrypoint",
-
-    "rand",
-    "chacha20poly1305",
-    "log",
-    "halo2_proofs",
-]

+ 0 - 75
src/contract/consensus/Makefile

@@ -1,75 +0,0 @@
-.POSIX:
-
-# Cargo binary
-CARGO = cargo +nightly
-
-# Compile target for system binaries
-RUST_TARGET = $(shell rustc -Vv | grep '^host: ' | cut -d' ' -f2)
-# Uncomment when doing musl static builds
-#RUSTFLAGS = -C target-feature=+crt-static -C link-self-contained=yes
-
-# wasm build target
-WASM_TARGET = wasm32-unknown-unknown
-
-# Cargo package name
-PKGNAME = $(shell grep '^name = ' Cargo.toml | cut -d' ' -f3 | tr -d '"')
-# wasm contract binary
-WASM_BIN = $(PKGNAME:=.wasm)
-
-# zkas compiler binary
-ZKAS = ../../../zkas
-
-# zkas circuits
-PROOFS_SRC = $(shell find proof -type f -name '*.zk')
-PROOFS_BIN = $(PROOFS_SRC:=.bin)
-
-# wasm source files
-WASM_SRC = \
-	Cargo.toml \
-	../../../Cargo.toml \
-	../../../src/sdk/Cargo.toml \
-	../../../src/serial/Cargo.toml \
-	$(shell find src -type f -name '*.rs') \
-	$(shell find ../../sdk -type f -name '*.rs') \
-	$(shell find ../../serial -type f -name '*.rs')
-
-all: $(WASM_BIN)
-
-$(PROOFS_BIN): $(ZKAS) $(PROOFS_SRC)
-	$(ZKAS) $(basename $@) -o $@
-
-$(WASM_BIN): $(WASM_SRC) $(PROOFS_BIN)
-	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) build --target=$(WASM_TARGET) \
-	--release --package $(PKGNAME)
-	cp -f ../../../target/$(WASM_TARGET)/release/$@ $@
-	wasm-strip $@
-
-test-stake-unstake: all
-	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) test --target=$(RUST_TARGET) \
-		--release --package $(PKGNAME) \
-		--features=no-entrypoint,client \
-		--test stake_unstake
-
-test-genesis-stake-unstake: all
-	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) test --target=$(RUST_TARGET) \
-		--release --package $(PKGNAME) \
-		--features=no-entrypoint,client \
-		--test genesis_stake_unstake
-
-test: test-genesis-stake-unstake test-stake-unstake
-
-clippy: all
-	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clippy --target=$(WASM_TARGET) \
-		--release --package $(PKGNAME)
-	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clippy --target=$(RUST_TARGET) \
-		--release --package $(PKGNAME) \
-		--features=no-entrypoint,client --tests
-
-clean:
-	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clean --target=$(WASM_TARGET) \
-		--release --package $(PKGNAME)
-	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clean --target=$(RUST_TARGET) \
-		--release --package $(PKGNAME)
-	rm -f $(PROOFS_BIN) $(WASM_BIN)
-
-.PHONY: all test-genesis-stake-unstake test-stake-unstake test clippy clean

+ 0 - 66
src/contract/consensus/proof/consensus_burn_v1.zk

@@ -1,66 +0,0 @@
-k = 13;
-field = "pallas";
-
-constant "ConsensusBurn_V1" {
-    EcFixedPointShort VALUE_COMMIT_VALUE,
-    EcFixedPoint VALUE_COMMIT_RANDOM,
-    EcFixedPointBase NULLIFIER_K,
-}
-
-witness "ConsensusBurn_V1" {
-    # The value of this coin
-    Base value,
-    # The epoch this coin was minted on
-    Base epoch,
-    # Unique serial number corresponding to this coin
-    Base serial,
-    # Random blinding factor for value commitment
-    Scalar value_blind,
-    # Secret key used to derive nullifier and coins' public key
-    Base secret,
-    # Leaf position of the coin in the Merkle tree of coins
-    Uint32 leaf_pos,
-    # Merkle path to the coin
-    MerklePath path,
-}
-
-circuit "ConsensusBurn_V1" {
-    # Poseidon hash of the nullifier
-    nullifier = poseidon_hash(secret, serial);
-    constrain_instance(nullifier);
-
-    # Constrain the epoch this coin was minted on
-    constrain_instance(epoch);
-
-    # We derive coins' public key for the signature and
-    # constrain its coordinates:
-    pub = ec_mul_base(secret, NULLIFIER_K);
-    pub_x = ec_get_x(pub);
-    pub_y = ec_get_y(pub);
-    constrain_instance(pub_x);
-    constrain_instance(pub_y);
-
-    # Coin hash
-    C = poseidon_hash(
-        pub_x,
-        pub_y,
-        value,
-        epoch,
-        serial,
-    );
-
-    # Merkle root
-    root = merkle_root(leaf_pos, path, C);
-    constrain_instance(root);
-
-    # Pedersen commitment for coin's value
-    vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
-    vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
-    value_commit = ec_add(vcv, vcr);
-    # Since value_commit is a curve point, we fetch its coordinates
-    # and constrain them:
-    constrain_instance(ec_get_x(value_commit));
-    constrain_instance(ec_get_y(value_commit));
-
-    # At this point we've enforced all of our public inputs.
-}

+ 0 - 48
src/contract/consensus/proof/consensus_mint_v1.zk

@@ -1,48 +0,0 @@
-k = 13;
-field = "pallas";
-
-constant "ConsensusMint_V1" {
-    EcFixedPointShort VALUE_COMMIT_VALUE,
-    EcFixedPoint VALUE_COMMIT_RANDOM,
-}
-
-witness "ConsensusMint_V1" {
-    # X coordinate for public key
-    Base pub_x,
-    # Y coordinate for public key
-    Base pub_y,
-    # The value of this coin
-    Base value,
-    # The epoch this coin was minted on
-    Base epoch,
-    # Unique serial number corresponding to this coin
-    Base serial,
-    # Random blinding factor for the value commitment
-    Scalar value_blind,
-}
-
-circuit "ConsensusMint_V1" {
-    # Constrain the epoch this coin was minted on
-    constrain_instance(epoch);
-
-    # Poseidon hash of the coin
-    C = poseidon_hash(
-        pub_x,
-        pub_y,
-        value,
-        epoch,
-        serial,
-    );
-    constrain_instance(C);
-
-    # Pedersen commitment for coin's value
-    vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
-    vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
-    value_commit = ec_add(vcv, vcr);
-    # Since the value commit is a curve point, we fetch its coordinates
-    # and constrain them:
-    constrain_instance(ec_get_x(value_commit));
-    constrain_instance(ec_get_y(value_commit));
-
-    # At this point we've enforced all of our public inputs.
-}

+ 0 - 157
src/contract/consensus/proof/consensus_proposal_v1.zk

@@ -1,157 +0,0 @@
-k = 13;
-field = "pallas";
-
-constant "ConsensusProposal_V1" {
-    EcFixedPointShort VALUE_COMMIT_VALUE,
-    EcFixedPoint VALUE_COMMIT_RANDOM,
-    EcFixedPointBase NULLIFIER_K,
-}
-
-witness "ConsensusProposal_V1" {
-    # Burnt coin secret key
-    Base input_secret_key,
-    # Unique serial number corresponding to the burnt coin
-    Base input_serial,
-    # The value of the burnt coin
-    Base input_value,
-    # The epoch the burnt coin was minted on
-    Base epoch,
-    # The reward value
-    Base reward,
-    # Random blinding factor for the value commitment
-    Scalar input_value_blind,
-    # Leaf position of the coin in the Merkle tree of coins
-    Uint32 leaf_pos,
-    # Merkle path to the coin
-    MerklePath path,
-    # Random blinding factor for the value commitment of the new coin
-    Scalar output_value_blind,
-    # Election seed y
-    Base mu_y,
-    # Election seed rho
-    Base mu_rho,
-    # Sigma1
-    Base sigma1,
-    # Sigma2
-    Base sigma2,
-    # Lottery headstart
-    Base headstart,
-}
-
-circuit "ConsensusProposal_V1" {
-    # Witnessed constants
-    ZERO = witness_base(0);
-    SERIAL_PREFIX = witness_base(2);
-    SEED_PREFIX = witness_base(3);
-    SECRET_PREFIX = witness_base(4);
-
-    # =============
-    # Burn old coin
-    # =============
-
-    # Poseidon hash of the nullifier
-    nullifier = poseidon_hash(input_secret_key, input_serial);
-    constrain_instance(nullifier);
-
-    # Constrain the epoch this coin was minted on.
-    # We use this as our timelock mechanism.
-    constrain_instance(epoch);
-
-    # We derive the coin's public key for the signature and
-    # VRF proof verification and constrain its coordinates:
-    input_pub = ec_mul_base(input_secret_key, NULLIFIER_K);
-    pub_x = ec_get_x(input_pub);
-    pub_y = ec_get_y(input_pub);
-    constrain_instance(pub_x);
-    constrain_instance(pub_y);
-
-    # Construct the burned coin
-    C = poseidon_hash(
-        pub_x,
-        pub_y,
-        input_value,
-        epoch,
-        input_serial,
-    );
-
-    # Merkle inclusion proof
-    root = merkle_root(leaf_pos, path, C);
-    constrain_instance(root);
-
-    # Pedersen commitment for burned coin's value
-    vcv = ec_mul_short(input_value, VALUE_COMMIT_VALUE);
-    vcr = ec_mul(input_value_blind, VALUE_COMMIT_RANDOM);
-    value_commit = ec_add(vcv, vcr);
-    # Since value_commit is a curve point, we fetch its coordinates
-    # and constrain them:
-    constrain_instance(ec_get_x(value_commit));
-    constrain_instance(ec_get_y(value_commit));
-
-    # =============
-    # Mint new coin
-    # =============
-
-    # Constrain reward value
-    constrain_instance(reward);
-
-    # Pedersen commitment for new coin's value (old value + reward)
-    output_value = base_add(input_value, reward);
-    nvcv = ec_mul_short(output_value, VALUE_COMMIT_VALUE);
-    nvcr = ec_mul(output_value_blind, VALUE_COMMIT_RANDOM);
-    output_value_commit = ec_add(nvcv, nvcr);
-    # Since the new value commit is also a curve point, we'll do the same
-    # coordinate dance:
-    constrain_instance(ec_get_x(output_value_commit));
-    constrain_instance(ec_get_y(output_value_commit));
-
-    # The serial of the new coin is derived from the old coin
-    output_serial = poseidon_hash(SERIAL_PREFIX, input_secret_key, input_serial);
-
-    # The secret key of the new coin is derived from old coin
-    output_secret_key = poseidon_hash(SECRET_PREFIX, input_secret_key);
-    output_pub = ec_mul_base(output_secret_key, NULLIFIER_K);
-    output_pub_x = ec_get_x(output_pub);
-    output_pub_y = ec_get_y(output_pub);
-
-    # Poseidon hash of the new coin
-    # In here we set the new epoch as ZERO, thus removing a
-    # potentially existing timelock.
-    output_coin = poseidon_hash(
-        output_pub_x,
-        output_pub_y,
-        output_value,
-        ZERO,
-        output_serial,
-    );
-    constrain_instance(output_coin);
-
-    # ============================
-    # Constrain lottery parameters
-    # ============================
-
-    # Coin y, constructed with the old serial for seeding:
-    seed = poseidon_hash(SEED_PREFIX, input_serial);
-    y = poseidon_hash(seed, mu_y);
-    constrain_instance(mu_y);
-    constrain_instance(y);
-
-    # Coin rho (seed):
-    rho = poseidon_hash(seed, mu_rho);
-    constrain_instance(mu_rho);
-    constrain_instance(rho);
-
-    # Calculate lottery target
-    term_1 = base_mul(sigma1, input_value);
-    term_2 = base_mul(sigma2, input_value);
-    shifted_term_2 = base_mul(term_2, input_value);
-    target = base_add(term_1, shifted_term_2);
-    shifted_target = base_add(target, headstart);
-    constrain_instance(sigma1);
-    constrain_instance(sigma2);
-    constrain_instance(headstart);
-
-    # Play lottery
-    less_than_strict(y, shifted_target);
-
-    # At this point we've enforced all of our public inputs.
-}

+ 0 - 179
src/contract/consensus/src/client/common.rs

@@ -1,179 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! This API is crufty. Please rework it into something nice to read and nice to use.
-
-use darkfi::{
-    zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit},
-    zkas::ZkBinary,
-    Result,
-};
-use darkfi_money_contract::{client::ConsensusNote, model::Coin};
-use darkfi_sdk::{
-    bridgetree,
-    bridgetree::Hashable,
-    crypto::{
-        pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, MerkleNode, Nullifier, PublicKey,
-        SecretKey,
-    },
-    pasta::pallas,
-};
-use rand::rngs::OsRng;
-
-pub struct ConsensusMintOutputInfo {
-    pub value: u64,
-    pub epoch: u64,
-    pub public_key: PublicKey,
-    pub value_blind: pallas::Scalar,
-    pub serial: pallas::Base,
-}
-
-pub struct ConsensusBurnInputInfo {
-    pub leaf_position: bridgetree::Position,
-    pub merkle_path: Vec<MerkleNode>,
-    pub secret: SecretKey,
-    pub note: ConsensusNote,
-    pub value_blind: pallas::Scalar,
-}
-
-pub struct ConsensusMintRevealed {
-    pub epoch: u64,
-    pub coin: Coin,
-    pub value_commit: pallas::Point,
-}
-
-impl ConsensusMintRevealed {
-    pub fn to_vec(&self) -> Vec<pallas::Base> {
-        let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
-
-        // NOTE: It's important to keep these in the same order
-        // as the `constrain_instance` calls in the zkas code.
-        vec![self.epoch.into(), self.coin.inner(), *valcom_coords.x(), *valcom_coords.y()]
-    }
-}
-
-/// Create a ZK proof for minting a coin in the Consensus coin state.
-pub fn create_consensus_mint_proof(
-    zkbin: &ZkBinary,
-    pk: &ProvingKey,
-    output: &ConsensusMintOutputInfo,
-) -> Result<(Proof, ConsensusMintRevealed)> {
-    let epoch_pallas = pallas::Base::from(output.epoch);
-    let value_pallas = pallas::Base::from(output.value);
-    let value_commit = pedersen_commitment_u64(output.value, output.value_blind);
-    let (pub_x, pub_y) = output.public_key.xy();
-
-    let coin = Coin::from(poseidon_hash([pub_x, pub_y, value_pallas, epoch_pallas, output.serial]));
-
-    let public_inputs = ConsensusMintRevealed { epoch: output.epoch, coin, value_commit };
-
-    let prover_witnesses = vec![
-        Witness::Base(Value::known(pub_x)),
-        Witness::Base(Value::known(pub_y)),
-        Witness::Base(Value::known(value_pallas)),
-        Witness::Base(Value::known(epoch_pallas)),
-        Witness::Base(Value::known(output.serial)),
-        Witness::Scalar(Value::known(output.value_blind)),
-    ];
-
-    let circuit = ZkCircuit::new(prover_witnesses, zkbin);
-    let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
-
-    Ok((proof, public_inputs))
-}
-
-pub struct ConsensusBurnRevealed {
-    pub nullifier: Nullifier,
-    pub epoch: u64,
-    pub signature_public: PublicKey,
-    pub merkle_root: MerkleNode,
-    pub value_commit: pallas::Point,
-}
-
-impl ConsensusBurnRevealed {
-    pub fn to_vec(&self) -> Vec<pallas::Base> {
-        let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
-        let sigpub_coords = self.signature_public.inner().to_affine().coordinates().unwrap();
-        let epoch_palas = pallas::Base::from(self.epoch);
-
-        // NOTE: It's important to keep these in the same order
-        // as the `constrain_instance` calls in the zkas code.
-        vec![
-            self.nullifier.inner(),
-            epoch_palas,
-            *sigpub_coords.x(),
-            *sigpub_coords.y(),
-            self.merkle_root.inner(),
-            *valcom_coords.x(),
-            *valcom_coords.y(),
-        ]
-    }
-}
-
-pub fn create_consensus_burn_proof(
-    zkbin: &ZkBinary,
-    pk: &ProvingKey,
-    input: &ConsensusBurnInputInfo,
-) -> Result<(Proof, ConsensusBurnRevealed, SecretKey)> {
-    let nullifier = Nullifier::from(poseidon_hash([input.secret.inner(), input.note.serial]));
-    let epoch = input.note.epoch;
-    let epoch_pallas = pallas::Base::from(epoch);
-    let value_pallas = pallas::Base::from(input.note.value);
-    let value_commit = pedersen_commitment_u64(input.note.value, input.value_blind);
-    let public_key = PublicKey::from_secret(input.secret);
-    let (pub_x, pub_y) = public_key.xy();
-
-    let coin = poseidon_hash([pub_x, pub_y, value_pallas, epoch_pallas, input.note.serial]);
-
-    let merkle_root = {
-        let position: u64 = input.leaf_position.into();
-        let mut current = MerkleNode::from(coin);
-        for (level, sibling) in input.merkle_path.iter().enumerate() {
-            let level = level as u8;
-            current = if position & (1 << level) == 0 {
-                MerkleNode::combine(level.into(), &current, sibling)
-            } else {
-                MerkleNode::combine(level.into(), sibling, &current)
-            };
-        }
-        current
-    };
-
-    let public_inputs = ConsensusBurnRevealed {
-        nullifier,
-        epoch,
-        signature_public: public_key,
-        merkle_root,
-        value_commit,
-    };
-
-    let prover_witnesses = vec![
-        Witness::Base(Value::known(value_pallas)),
-        Witness::Base(Value::known(epoch_pallas)),
-        Witness::Base(Value::known(input.note.serial)),
-        Witness::Scalar(Value::known(input.value_blind)),
-        Witness::Base(Value::known(input.secret.inner())),
-        Witness::Uint32(Value::known(u64::from(input.leaf_position).try_into().unwrap())),
-        Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
-    ];
-
-    let circuit = ZkCircuit::new(prover_witnesses, zkbin);
-    let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
-
-    Ok((proof, public_inputs, input.secret))
-}

+ 0 - 143
src/contract/consensus/src/client/genesis_stake_v1.rs

@@ -1,143 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! This API is crufty. Please rework it into something nice to read and nice to use.
-
-use darkfi::{
-    zk::{Proof, ProvingKey},
-    zkas::ZkBinary,
-    Result,
-};
-use darkfi_money_contract::{
-    client::ConsensusNote,
-    model::{ClearInput, ConsensusOutput},
-};
-use darkfi_sdk::{
-    crypto::{note::AeadEncryptedNote, pasta_prelude::*, Keypair, PublicKey, DARK_TOKEN_ID},
-    pasta::pallas,
-};
-use log::{debug, info};
-use rand::rngs::OsRng;
-
-use crate::{
-    client::common::{create_consensus_mint_proof, ConsensusMintOutputInfo},
-    model::ConsensusGenesisStakeParamsV1,
-};
-
-pub struct ConsensusGenesisStakeCallDebris {
-    pub params: ConsensusGenesisStakeParamsV1,
-    pub proofs: Vec<Proof>,
-}
-
-/// Struct holding necessary information to build a `Consensus::GenesisStakeV1` contract call.
-pub struct ConsensusGenesisStakeCallBuilder {
-    /// Signer keypair, this pubkey is in the clear input, and used to sign the tx.
-    pub keypair: Keypair,
-    /// Output pubkey, to whom the minted coin goes. The secret should be managed externally.
-    pub recipient: PublicKey,
-    /// Amount of tokens we want to mint and stake
-    pub amount: u64,
-    /// `ConsensusMint_V1` zkas circuit ZkBinary
-    pub mint_zkbin: ZkBinary,
-    /// Proving key for the `ConsensusMint_V1` zk circuit
-    pub mint_pk: ProvingKey,
-}
-
-impl ConsensusGenesisStakeCallBuilder {
-    pub fn build(&self) -> Result<ConsensusGenesisStakeCallDebris> {
-        // We just create the pedersen commitment blinds here. We simply
-        // enforce that the clear input and the anon output have the same
-        // commitments.
-        let value_blind = pallas::Scalar::random(&mut OsRng);
-        let token_blind = pallas::Base::random(&mut OsRng);
-        let reward_blind = pallas::Scalar::random(&mut OsRng);
-
-        // FIXME: The coin's serial number here is arbitrary, and allows grinding attacks.
-        let serial = pallas::Base::random(&mut OsRng);
-
-        self.build_with_params(value_blind, token_blind, reward_blind, serial)
-    }
-
-    pub fn build_with_params(
-        &self,
-        value_blind: pallas::Scalar,
-        token_blind: pallas::Base,
-        reward_blind: pallas::Scalar,
-        serial: pallas::Base,
-    ) -> Result<ConsensusGenesisStakeCallDebris> {
-        debug!("Building Consensus::GenesisStakeV1 contract call");
-        let value = self.amount;
-        assert!(value != 0);
-
-        // In this call, we will build one clear input and one anonymous output.
-        // Only DARK_TOKEN_ID can be minted and staked on genesis slot.
-        let token_id = *DARK_TOKEN_ID;
-
-        // With genesis, our epoch is 0.
-        let epoch = 0;
-
-        // Parameters for the clear input
-        let c_input = ClearInput {
-            value,
-            token_id,
-            value_blind,
-            token_blind,
-            signature_public: self.keypair.public,
-        };
-
-        // Parameters for the anonymous output
-        let output = ConsensusMintOutputInfo {
-            value,
-            epoch,
-            public_key: self.recipient,
-            value_blind,
-            serial,
-        };
-
-        info!("Creating genesis stake mint proof for output");
-        let (proof, public_inputs) =
-            create_consensus_mint_proof(&self.mint_zkbin, &self.mint_pk, &output)?;
-
-        // Encrypted note
-        let note = ConsensusNote {
-            serial,
-            value: output.value,
-            epoch,
-            value_blind,
-            reward: 0,
-            reward_blind,
-        };
-
-        let encrypted_note = AeadEncryptedNote::encrypt(&note, &self.recipient, &mut OsRng)?;
-
-        let output = ConsensusOutput {
-            value_commit: public_inputs.value_commit,
-            coin: public_inputs.coin,
-            note: encrypted_note,
-        };
-
-        // We now fill this with necessary stuff
-        let params = ConsensusGenesisStakeParamsV1 { input: c_input, output };
-        let proofs = vec![proof];
-
-        // Now we should have all the params and zk proof.
-        // We return it all and let the caller deal with it.
-        let debris = ConsensusGenesisStakeCallDebris { params, proofs };
-        Ok(debris)
-    }
-}

+ 0 - 44
src/contract/consensus/src/client/mod.rs

@@ -1,44 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! This module implements the client-side API for this contract's interaction.
-//! What we basically do here is implement an API that creates the necessary
-//! structures and is able to export them to create a DarkFi transaction
-//! object that can be broadcasted to the network.
-//!
-//! Note that this API does not involve any wallet interaction, but only takes
-//! the necessary objects provided by the caller. This is intentional, so we
-//! are able to abstract away any wallet interfaces to client implementations.
-
-/// Common functions
-pub(crate) mod common;
-
-/// `Consensus::GenesisStakeV1` API
-pub mod genesis_stake_v1;
-
-/// `Consensus::StakeV1` API
-pub mod stake_v1;
-
-/// Proposal transaction building API.
-pub mod proposal_v1;
-
-/// `Consensus::UnstakeRequestV1` API
-pub mod unstake_request_v1;
-
-/// `Consensus::UnstakeV1` API
-pub mod unstake_v1;

+ 0 - 359
src/contract/consensus/src/client/proposal_v1.rs

@@ -1,359 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! This API is crufty. Please rework it into something nice to read and nice to use.
-
-use darkfi::{
-    error::Error::CoinIsNotSlotProducer,
-    zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit},
-    zkas::ZkBinary,
-    Result,
-};
-use darkfi_money_contract::{
-    client::{ConsensusNote, ConsensusOwnCoin},
-    model::{Coin, ConsensusInput, ConsensusOutput},
-};
-use darkfi_sdk::{
-    blockchain::Slot,
-    bridgetree::Hashable,
-    crypto::{
-        ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_u64,
-        poseidon_hash, Keypair, MerkleNode, MerkleTree, Nullifier, PublicKey, SecretKey,
-    },
-    pasta::{group::ff::FromUniformBytes, pallas},
-};
-use log::{debug, error, info};
-use rand::rngs::OsRng;
-
-use crate::{
-    client::common::{ConsensusBurnInputInfo, ConsensusMintOutputInfo},
-    model::{
-        ConsensusProposalParamsV1, HEADSTART, MU_RHO_PREFIX, MU_Y_PREFIX, REWARD,
-        SECRET_KEY_PREFIX, SEED_PREFIX, SERIAL_PREFIX,
-    },
-};
-
-pub struct ConsensusProposalCallDebris {
-    /// Payload params
-    pub params: ConsensusProposalParamsV1,
-    /// ZK proofs
-    pub proofs: Vec<Proof>,
-    /// The new output keypair (used in the minted coin)
-    pub keypair: Keypair,
-    /// Secret key used to sign the transaction
-    pub signature_secret: SecretKey,
-}
-
-pub struct ConsensusProposalRevealed {
-    pub nullifier: Nullifier,
-    pub epoch: u64,
-    pub public_key: PublicKey,
-    pub merkle_root: MerkleNode,
-    pub input_value_commit: pallas::Point,
-    pub reward: u64,
-    pub output_value_commit: pallas::Point,
-    pub output_coin: Coin,
-    pub vrf_proof: VrfProof,
-    pub mu_y: pallas::Base,
-    pub y: pallas::Base,
-    pub mu_rho: pallas::Base,
-    pub rho: pallas::Base,
-    pub sigma1: pallas::Base,
-    pub sigma2: pallas::Base,
-    pub headstart: pallas::Base,
-}
-
-impl ConsensusProposalRevealed {
-    fn to_vec(&self) -> Vec<pallas::Base> {
-        let (pub_x, pub_y) = self.public_key.xy();
-        let input_value_coords = self.input_value_commit.to_affine().coordinates().unwrap();
-        let output_value_coords = self.output_value_commit.to_affine().coordinates().unwrap();
-
-        // NOTE: It's important to keep these in the same order
-        // as the `constrain_instance` calls in the zkas code.
-        vec![
-            self.nullifier.inner(),
-            pallas::Base::from(self.epoch),
-            pub_x,
-            pub_y,
-            self.merkle_root.inner(),
-            *input_value_coords.x(),
-            *input_value_coords.y(),
-            pallas::Base::from(self.reward),
-            *output_value_coords.x(),
-            *output_value_coords.y(),
-            self.output_coin.inner(),
-            self.mu_y,
-            self.y,
-            self.mu_rho,
-            self.rho,
-            self.sigma1,
-            self.sigma2,
-            self.headstart,
-        ]
-    }
-}
-
-/// Struct holding necessary information to build a proposal transaction.
-pub struct ConsensusProposalCallBuilder {
-    /// `ConsensusOwnCoin` we're given to use in this builder
-    pub owncoin: ConsensusOwnCoin,
-    /// Rewarded slot
-    pub slot: Slot,
-    /// Extending fork last proposal/block hash
-    pub fork_hash: blake3::Hash,
-    /// Extending fork second to last proposal/block hash
-    pub fork_previous_hash: blake3::Hash,
-    /// Merkle tree of coins used to create inclusion proofs
-    pub merkle_tree: MerkleTree,
-    /// `Proposal_V1` zkas circuit ZkBinary
-    pub proposal_zkbin: ZkBinary,
-    /// Proving key for the `Proposal_V1` zk circuit
-    pub proposal_pk: ProvingKey,
-}
-
-impl ConsensusProposalCallBuilder {
-    pub fn build(&self) -> Result<ConsensusProposalCallDebris> {
-        let input_value_blind = pallas::Scalar::random(&mut OsRng);
-        let output_reward_blind = pallas::Scalar::random(&mut OsRng);
-
-        self.build_with_params(input_value_blind, output_reward_blind)
-    }
-
-    pub fn build_with_params(
-        &self,
-        input_value_blind: pallas::Scalar,
-        output_reward_blind: pallas::Scalar,
-    ) -> Result<ConsensusProposalCallDebris> {
-        info!("Building Consensus::ProposalBurnV1 contract call");
-        assert!(self.owncoin.note.value != 0);
-
-        debug!("Building Consensus::ProposalV1 anonymous input");
-        let merkle_path = self.merkle_tree.witness(self.owncoin.leaf_position, 0).unwrap();
-
-        let input = ConsensusBurnInputInfo {
-            leaf_position: self.owncoin.leaf_position,
-            merkle_path,
-            secret: self.owncoin.secret,
-            note: self.owncoin.note.clone(),
-            value_blind: input_value_blind,
-        };
-
-        debug!("Building Consensus::ProposalV1 anonymous output");
-        let output_value_blind = input.value_blind + output_reward_blind;
-
-        // The output's secret key is derived from the old secret key
-        let output_secret_key = poseidon_hash([SECRET_KEY_PREFIX, self.owncoin.secret.inner()]);
-        let output_keypair = Keypair::new(SecretKey::from(output_secret_key));
-
-        // The output's serial is derived from the old serial
-        let output_serial =
-            poseidon_hash([SERIAL_PREFIX, self.owncoin.secret.inner(), self.owncoin.note.serial]);
-
-        let output = ConsensusMintOutputInfo {
-            value: self.owncoin.note.value + REWARD,
-            epoch: 0, // We set the epoch as 0 here to eliminate a potential timelock
-            public_key: output_keypair.public,
-            value_blind: output_value_blind,
-            serial: output_serial,
-        };
-
-        info!("Building Consensus::ProposalV1 VRF proof");
-        let mut vrf_input = Vec::with_capacity(32 + blake3::OUT_LEN + 32);
-        vrf_input.extend_from_slice(&self.slot.last_nonce.to_repr());
-        vrf_input.extend_from_slice(self.fork_previous_hash.as_bytes());
-        vrf_input.extend_from_slice(&pallas::Base::from(self.slot.id).to_repr());
-        let vrf_proof = VrfProof::prove(input.secret, &vrf_input, &mut OsRng);
-
-        info!("Building Consensus::ProposalV1 ZK proof");
-        let (proof, public_inputs) = create_proposal_proof(
-            &self.proposal_zkbin,
-            &self.proposal_pk,
-            &input,
-            &output,
-            &self.slot,
-            &vrf_proof,
-        )?;
-
-        let tx_input = ConsensusInput {
-            epoch: input.note.epoch,
-            value_commit: public_inputs.input_value_commit,
-            nullifier: public_inputs.nullifier,
-            merkle_root: public_inputs.merkle_root,
-            signature_public: public_inputs.public_key,
-        };
-
-        // Output's encrypted note
-        let note = ConsensusNote {
-            serial: output.serial,
-            value: output.value,
-            epoch: output.epoch,
-            value_blind: output.value_blind,
-            reward: REWARD,
-            reward_blind: output_reward_blind,
-        };
-
-        let encrypted_note = AeadEncryptedNote::encrypt(&note, &output.public_key, &mut OsRng)?;
-
-        let tx_output = ConsensusOutput {
-            value_commit: public_inputs.output_value_commit,
-            coin: public_inputs.output_coin,
-            note: encrypted_note,
-        };
-
-        // Construct params
-        let params = ConsensusProposalParamsV1 {
-            input: tx_input,
-            output: tx_output,
-            reward: REWARD,
-            reward_blind: output_reward_blind,
-            fork_hash: self.fork_hash,
-            fork_previous_hash: self.fork_previous_hash,
-            vrf_proof,
-            y: public_inputs.y,
-            rho: public_inputs.rho,
-        };
-
-        // Construct debris
-        let debris = ConsensusProposalCallDebris {
-            params,
-            proofs: vec![proof],
-            keypair: output_keypair,
-            signature_secret: input.secret,
-        };
-        Ok(debris)
-    }
-}
-
-fn create_proposal_proof(
-    zkbin: &ZkBinary,
-    pk: &ProvingKey,
-    input: &ConsensusBurnInputInfo,
-    output: &ConsensusMintOutputInfo,
-    slot: &Slot,
-    vrf_proof: &VrfProof,
-) -> Result<(Proof, ConsensusProposalRevealed)> {
-    // TODO: fork_hash to be used as part of rank constrain in the proof
-    // Calculate lottery parameters
-    let seed = poseidon_hash([SEED_PREFIX, input.note.serial]);
-
-    let mut eta = [0u8; 64];
-    eta[..blake3::OUT_LEN].copy_from_slice(vrf_proof.hash_output().as_bytes());
-    let eta = pallas::Base::from_uniform_bytes(&eta);
-
-    let mu_y = poseidon_hash([MU_Y_PREFIX, eta, pallas::Base::from(slot.id)]);
-    let y = poseidon_hash([seed, mu_y]);
-    let mu_rho = poseidon_hash([MU_RHO_PREFIX, eta, pallas::Base::from(slot.id)]);
-    let rho = poseidon_hash([seed, mu_rho]);
-
-    // Verify coin is the slot block producer
-    let value_pallas = pallas::Base::from(input.note.value);
-    let shifted_target =
-        slot.pid.sigma1 * value_pallas + slot.pid.sigma2 * value_pallas * value_pallas + HEADSTART;
-
-    if y >= shifted_target {
-        error!("MU_Y: {:?}", mu_y);
-        error!("Y: {:?}", y);
-        error!("TARGET: {:?}", shifted_target);
-        return Err(CoinIsNotSlotProducer)
-    }
-
-    // Derive the input's nullifier
-    let nullifier = Nullifier::from(poseidon_hash([input.secret.inner(), input.note.serial]));
-
-    // Create the value commitment for the input
-    let input_value_commit = pedersen_commitment_u64(input.note.value, input.value_blind);
-
-    // Merkle inclusion proof for the input
-    let public_key = PublicKey::from_secret(input.secret);
-    let (pub_x, pub_y) = public_key.xy();
-
-    let coin = poseidon_hash([
-        pub_x,
-        pub_y,
-        pallas::Base::from(input.note.value),
-        pallas::Base::from(input.note.epoch),
-        input.note.serial,
-    ]);
-
-    let merkle_root = {
-        let position: u64 = input.leaf_position.into();
-        let mut current = MerkleNode::from(coin);
-        for (level, sibling) in input.merkle_path.iter().enumerate() {
-            let level = level as u8;
-            current = if position & (1 << level) == 0 {
-                MerkleNode::combine(level.into(), &current, sibling)
-            } else {
-                MerkleNode::combine(level.into(), sibling, &current)
-            };
-        }
-        current
-    };
-
-    // Derive the new output coin
-    let (output_x, output_y) = output.public_key.xy();
-    let output_coin = Coin::from(poseidon_hash([
-        output_x,
-        output_y,
-        pallas::Base::from(output.value),
-        pallas::Base::from(output.epoch),
-        output.serial,
-    ]));
-
-    // Create the ZK proof
-    let public_inputs = ConsensusProposalRevealed {
-        nullifier,
-        epoch: input.note.epoch,
-        public_key,
-        merkle_root,
-        input_value_commit,
-        reward: REWARD,
-        output_value_commit: pedersen_commitment_u64(output.value, output.value_blind),
-        output_coin,
-        vrf_proof: *vrf_proof,
-        mu_y,
-        y,
-        mu_rho,
-        rho,
-        sigma1: slot.pid.sigma1,
-        sigma2: slot.pid.sigma2,
-        headstart: HEADSTART,
-    };
-
-    let prover_witnesses = vec![
-        Witness::Base(Value::known(input.secret.inner())),
-        Witness::Base(Value::known(input.note.serial)),
-        Witness::Base(Value::known(pallas::Base::from(input.note.value))),
-        Witness::Base(Value::known(pallas::Base::from(input.note.epoch))),
-        Witness::Base(Value::known(pallas::Base::from(REWARD))),
-        Witness::Scalar(Value::known(input.value_blind)),
-        Witness::Uint32(Value::known(u64::from(input.leaf_position).try_into().unwrap())),
-        Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
-        Witness::Scalar(Value::known(output.value_blind)),
-        Witness::Base(Value::known(public_inputs.mu_y)),
-        Witness::Base(Value::known(public_inputs.mu_rho)),
-        Witness::Base(Value::known(public_inputs.sigma1)),
-        Witness::Base(Value::known(public_inputs.sigma2)),
-        Witness::Base(Value::known(public_inputs.headstart)),
-    ];
-
-    let circuit = ZkCircuit::new(prover_witnesses, zkbin);
-    let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
-
-    Ok((proof, public_inputs))
-}

+ 0 - 117
src/contract/consensus/src/client/stake_v1.rs

@@ -1,117 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! This API is crufty. Please rework it into something nice to read and nice to use.
-
-use darkfi::{
-    zk::{Proof, ProvingKey},
-    zkas::ZkBinary,
-    Result,
-};
-use darkfi_money_contract::{
-    client::{ConsensusNote, OwnCoin},
-    model::{ConsensusOutput, ConsensusStakeParamsV1, Input},
-};
-use darkfi_sdk::{
-    crypto::{note::AeadEncryptedNote, pasta_prelude::*, PublicKey, SecretKey, DARK_TOKEN_ID},
-    pasta::pallas,
-};
-use log::{debug, info};
-use rand::rngs::OsRng;
-
-use crate::client::common::{create_consensus_mint_proof, ConsensusMintOutputInfo};
-
-pub struct ConsensusStakeCallDebris {
-    pub params: ConsensusStakeParamsV1,
-    pub proofs: Vec<Proof>,
-    pub signature_secret: SecretKey,
-}
-
-/// Struct holding necessary information to build a `Consensus::StakeV1` contract call.
-pub struct ConsensusStakeCallBuilder {
-    /// `OwnCoin` we're given to use in this builder
-    pub coin: OwnCoin,
-    /// Epoch staked coin is minted
-    pub epoch: u64,
-    /// Blinding factor for value commitment
-    pub value_blind: pallas::Scalar,
-    /// The money `Input` (comes from the previous `Money::Stake` contract call)
-    pub money_input: Input,
-    /// `ConsensusMint_V1` zkas circuit ZkBinary
-    pub mint_zkbin: ZkBinary,
-    /// Proving key for the `ConsensusMint_V1` zk circuit
-    pub mint_pk: ProvingKey,
-}
-
-impl ConsensusStakeCallBuilder {
-    pub fn build(&self) -> Result<ConsensusStakeCallDebris> {
-        let serial = pallas::Base::random(&mut OsRng);
-
-        self.build_with_params(serial)
-    }
-
-    pub fn build_with_params(&self, serial: pallas::Base) -> Result<ConsensusStakeCallDebris> {
-        debug!("Building Consensus::StakeV1 contract call");
-        assert!(self.coin.note.value != 0);
-        assert!(self.coin.note.token_id == *DARK_TOKEN_ID);
-
-        debug!("Building anonymous output");
-        let public_key = PublicKey::from_secret(self.coin.secret);
-
-        let output = ConsensusMintOutputInfo {
-            value: self.coin.note.value,
-            epoch: self.epoch,
-            public_key,
-            value_blind: self.value_blind,
-            serial,
-        };
-        debug!("Finished building output");
-
-        info!("Creating stake mint proof for output");
-        let (proof, public_inputs) =
-            create_consensus_mint_proof(&self.mint_zkbin, &self.mint_pk, &output)?;
-
-        // Encrypted note
-        let note = ConsensusNote {
-            serial,
-            value: output.value,
-            epoch: self.epoch,
-            value_blind: self.value_blind,
-            reward: 0,
-            reward_blind: self.value_blind,
-        };
-
-        let encrypted_note = AeadEncryptedNote::encrypt(&note, &output.public_key, &mut OsRng)?;
-
-        let output = ConsensusOutput {
-            value_commit: public_inputs.value_commit,
-            coin: public_inputs.coin,
-            note: encrypted_note,
-        };
-
-        // We now fill this with necessary stuff
-        let params = ConsensusStakeParamsV1 { input: self.money_input.clone(), output };
-        let proofs = vec![proof];
-
-        // Now we should have all the params and zk proof.
-        // We return it all and let the caller deal with it.
-        let debris =
-            ConsensusStakeCallDebris { params, proofs, signature_secret: self.coin.secret };
-        Ok(debris)
-    }
-}

+ 0 - 165
src/contract/consensus/src/client/unstake_request_v1.rs

@@ -1,165 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! This API is crufty. Please rework it into something nice to read and nice to use.
-
-use darkfi::{
-    zk::{Proof, ProvingKey},
-    zkas::ZkBinary,
-    Result,
-};
-use darkfi_money_contract::{
-    client::{ConsensusNote, ConsensusOwnCoin},
-    model::{ConsensusInput, ConsensusOutput, ConsensusUnstakeReqParamsV1},
-};
-use darkfi_sdk::{
-    crypto::{
-        note::AeadEncryptedNote, pasta_prelude::*, poseidon_hash, Keypair, MerkleTree, SecretKey,
-    },
-    pasta::pallas,
-};
-use log::{debug, info};
-use rand::rngs::OsRng;
-
-use crate::{
-    client::common::{
-        create_consensus_burn_proof, create_consensus_mint_proof, ConsensusBurnInputInfo,
-        ConsensusMintOutputInfo,
-    },
-    model::{SECRET_KEY_PREFIX, SERIAL_PREFIX},
-};
-
-pub struct ConsensusUnstakeRequestCallDebris {
-    /// Payload params
-    pub params: ConsensusUnstakeReqParamsV1,
-    /// ZK proofs
-    pub proofs: Vec<Proof>,
-    /// The new output keypair (used in the minted coin)
-    pub keypair: Keypair,
-    /// Secret key used to sign the transaction
-    pub signature_secret: SecretKey,
-}
-
-/// Struct holding necessary information to build a `Consensus::UnstakeRequestV1` contract call.
-pub struct ConsensusUnstakeRequestCallBuilder {
-    /// `ConsensusOwnCoin` we're given to use in this builder
-    pub owncoin: ConsensusOwnCoin,
-    /// Epoch unstaked coin is minted
-    pub epoch: u64,
-    /// Merkle tree of coins used to create inclusion proofs
-    pub tree: MerkleTree,
-    /// `ConsensusBurn_V1` zkas circuit ZkBinary
-    pub burn_zkbin: ZkBinary,
-    /// Proving key for the `ConsensusBurn_V1` zk circuit
-    pub burn_pk: ProvingKey,
-    /// `ConsensusMint_V1` zkas circuit ZkBinary
-    pub mint_zkbin: ZkBinary,
-    /// Proving key for the `ConsensusMint_V1` zk circuit
-    pub mint_pk: ProvingKey,
-}
-
-impl ConsensusUnstakeRequestCallBuilder {
-    pub fn build(&self) -> Result<ConsensusUnstakeRequestCallDebris> {
-        let input_value_blind = pallas::Scalar::random(&mut OsRng);
-
-        self.build_with_params(input_value_blind)
-    }
-
-    pub fn build_with_params(
-        &self,
-        input_value_blind: pallas::Scalar,
-    ) -> Result<ConsensusUnstakeRequestCallDebris> {
-        info!("Building Consensus::UnstakeRequestV1 contract call");
-        assert!(self.owncoin.note.value != 0);
-
-        debug!("Building Consensus::UnstakeRequestV1 anonymous input");
-        let merkle_path = self.tree.witness(self.owncoin.leaf_position, 0).unwrap();
-
-        let input = ConsensusBurnInputInfo {
-            leaf_position: self.owncoin.leaf_position,
-            merkle_path,
-            secret: self.owncoin.secret,
-            note: self.owncoin.note.clone(),
-            value_blind: input_value_blind,
-        };
-
-        debug!("Building Consensus::UnstakeRequestV1 anonymous output");
-        // The output's secret key is derived from the old secret key
-        let output_secret_key = poseidon_hash([SECRET_KEY_PREFIX, self.owncoin.secret.inner()]);
-        let output_keypair = Keypair::new(SecretKey::from(output_secret_key));
-        let output_serial =
-            poseidon_hash([SERIAL_PREFIX, self.owncoin.secret.inner(), self.owncoin.note.serial]);
-
-        // We create a new random keypair for the output
-        //let output_keypair = Keypair::random(&mut OsRng);
-
-        let output = ConsensusMintOutputInfo {
-            value: self.owncoin.note.value,
-            epoch: self.epoch,
-            public_key: output_keypair.public,
-            value_blind: input.value_blind,
-            serial: output_serial,
-        };
-
-        info!("Building Consensus::UnstakeRequestV1 Burn ZK proof");
-        let (burn_proof, public_inputs, signature_secret) =
-            create_consensus_burn_proof(&self.burn_zkbin, &self.burn_pk, &input)?;
-
-        let tx_input = ConsensusInput {
-            epoch: self.owncoin.note.epoch,
-            value_commit: public_inputs.value_commit,
-            nullifier: public_inputs.nullifier,
-            merkle_root: public_inputs.merkle_root,
-            signature_public: public_inputs.signature_public,
-        };
-
-        info!("Building Consensus::UnstakeRequestV1 Mint ZK proof");
-        let (mint_proof, public_inputs) =
-            create_consensus_mint_proof(&self.mint_zkbin, &self.mint_pk, &output)?;
-
-        // Encrypted note
-        let note = ConsensusNote {
-            serial: output_serial,
-            value: output.value,
-            epoch: output.epoch,
-            value_blind: input.value_blind,
-            reward: 0,
-            reward_blind: pallas::Scalar::ZERO,
-        };
-
-        let encrypted_note = AeadEncryptedNote::encrypt(&note, &output.public_key, &mut OsRng)?;
-
-        let tx_output = ConsensusOutput {
-            value_commit: public_inputs.value_commit,
-            coin: public_inputs.coin,
-            note: encrypted_note,
-        };
-
-        // We now fill this with necessary stuff
-        let params = ConsensusUnstakeReqParamsV1 { input: tx_input, output: tx_output };
-
-        // Construct debris
-        let debris = ConsensusUnstakeRequestCallDebris {
-            params,
-            proofs: vec![burn_proof, mint_proof],
-            keypair: output_keypair,
-            signature_secret,
-        };
-        Ok(debris)
-    }
-}

+ 0 - 111
src/contract/consensus/src/client/unstake_v1.rs

@@ -1,111 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! This API is crufty. Please rework it into something nice to read and nice to use.
-
-use darkfi::{
-    zk::{Proof, ProvingKey},
-    zkas::ZkBinary,
-    Result,
-};
-use darkfi_money_contract::{
-    client::ConsensusOwnCoin,
-    model::{ConsensusInput, ConsensusUnstakeParamsV1},
-};
-use darkfi_sdk::{
-    crypto::{pasta_prelude::*, MerkleTree, SecretKey},
-    pasta::pallas,
-};
-use log::{debug, info};
-use rand::rngs::OsRng;
-
-use crate::client::common::{create_consensus_burn_proof, ConsensusBurnInputInfo};
-
-pub struct ConsensusUnstakeCallDebris {
-    /// Payload params
-    pub params: ConsensusUnstakeParamsV1,
-    /// ZK proofs
-    pub proofs: Vec<Proof>,
-    /// Secret key used to sign the transaction
-    pub signature_secret: SecretKey,
-    /// Value blind to be used in the `Money::UnstakeV1` call
-    pub value_blind: pallas::Scalar,
-}
-
-/// Struct holding necessary information to build a `Consensus::UnstakeV1` contract call.
-pub struct ConsensusUnstakeCallBuilder {
-    /// `ConsensusOwnCoin` we're given to use in this builder
-    pub owncoin: ConsensusOwnCoin,
-    /// Merkle tree of coins used to create inclusion proofs
-    pub tree: MerkleTree,
-    /// `ConsensusBurn_V1` zkas circuit ZkBinary
-    pub burn_zkbin: ZkBinary,
-    /// Proving key for the `ConsensusBurn_V1` zk circuit
-    pub burn_pk: ProvingKey,
-}
-
-impl ConsensusUnstakeCallBuilder {
-    pub fn build(&self) -> Result<ConsensusUnstakeCallDebris> {
-        let input_value_blind = pallas::Scalar::random(&mut OsRng);
-
-        self.build_with_params(input_value_blind)
-    }
-
-    pub fn build_with_params(
-        &self,
-        input_value_blind: pallas::Scalar,
-    ) -> Result<ConsensusUnstakeCallDebris> {
-        info!("Building Consensus::UnstakeV1 contract call");
-        assert!(self.owncoin.note.value != 0);
-
-        debug!("Building Consensus::UnstakeV1 anonymous input");
-        let merkle_path = self.tree.witness(self.owncoin.leaf_position, 0).unwrap();
-
-        let input = ConsensusBurnInputInfo {
-            leaf_position: self.owncoin.leaf_position,
-            merkle_path,
-            secret: self.owncoin.secret,
-            note: self.owncoin.note.clone(),
-            value_blind: input_value_blind,
-        };
-
-        info!("Building Consensus::UnstakeV1 Burn ZK proof");
-        let (proof, public_inputs, signature_secret) =
-            create_consensus_burn_proof(&self.burn_zkbin, &self.burn_pk, &input)?;
-
-        let tx_input = ConsensusInput {
-            epoch: self.owncoin.note.epoch,
-            value_commit: public_inputs.value_commit,
-            nullifier: public_inputs.nullifier,
-            merkle_root: public_inputs.merkle_root,
-            signature_public: public_inputs.signature_public,
-        };
-
-        // We now fill this with necessary stuff
-        let params = ConsensusUnstakeParamsV1 { input: tx_input };
-
-        // Construct debris
-        let debris = ConsensusUnstakeCallDebris {
-            params,
-            proofs: vec![proof],
-            signature_secret,
-            value_blind: input.value_blind,
-        };
-        Ok(debris)
-    }
-}

+ 0 - 264
src/contract/consensus/src/entrypoint.rs

@@ -1,264 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_money_contract::{
-    model::{ConsensusStakeUpdateV1, ConsensusUnstakeUpdateV1},
-    CONSENSUS_CONTRACT_DB_VERSION, CONSENSUS_CONTRACT_INFO_TREE,
-    CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
-    CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE,
-    CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE,
-    CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE,
-};
-use darkfi_sdk::{
-    crypto::{ContractId, MerkleTree},
-    dark_tree::DarkLeaf,
-    db::{db_init, db_lookup, db_set, zkas_db_set},
-    error::{ContractError, ContractResult},
-    msg,
-    util::set_return_data,
-    ContractCall,
-};
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
-
-use crate::{
-    model::{ConsensusGenesisStakeUpdateV1, ConsensusProposalUpdateV1},
-    ConsensusFunction,
-};
-
-/// `Consensus::GenesisStake` functions
-mod genesis_stake_v1;
-use genesis_stake_v1::{
-    consensus_genesis_stake_get_metadata_v1, consensus_genesis_stake_process_instruction_v1,
-    consensus_genesis_stake_process_update_v1,
-};
-
-/// `Consensus::Stake` functions
-mod stake_v1;
-use stake_v1::{
-    consensus_stake_get_metadata_v1, consensus_stake_process_instruction_v1,
-    consensus_stake_process_update_v1,
-};
-
-/// `Consensus::ProposalV1` functions
-mod proposal_v1;
-use proposal_v1::{
-    consensus_proposal_get_metadata_v1, consensus_proposal_process_instruction_v1,
-    consensus_proposal_process_update_v1,
-};
-
-/// `Consensus::UnstakeRequest` functions
-mod unstake_request_v1;
-use unstake_request_v1::{
-    consensus_unstake_request_get_metadata_v1, consensus_unstake_request_process_instruction_v1,
-    consensus_unstake_request_process_update_v1,
-};
-
-/// `Consensus::Unstake` functions
-mod unstake_v1;
-use unstake_v1::{
-    consensus_unstake_get_metadata_v1, consensus_unstake_process_instruction_v1,
-    consensus_unstake_process_update_v1,
-};
-
-darkfi_sdk::define_contract!(
-    init: init_contract,
-    exec: process_instruction,
-    apply: process_update,
-    metadata: get_metadata
-);
-
-/// This entrypoint function runs when the contract is (re)deployed and initialized.
-/// We use this function to initialize all the necessary databases and prepare them
-/// with initial data if necessary. This is also the place where we bundle the zkas
-/// circuits that are to be used with functions provided by the contract.
-fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
-    // zkas circuits can simply be embedded in the wasm and set up by using
-    // respective db functions. The special `zkas db` operations exist in
-    // order to be able to verify the circuits being bundled and enforcing
-    // a specific tree inside sled, and also creation of VerifyingKey.
-    let consensus_mint_v1_bincode = include_bytes!("../proof/consensus_mint_v1.zk.bin");
-    let consensus_burn_v1_bincode = include_bytes!("../proof/consensus_burn_v1.zk.bin");
-    let consensus_proposal_v1_bincode = include_bytes!("../proof/consensus_proposal_v1.zk.bin");
-
-    // For that, we use `zkas_db_set` and pass in the bincode.
-    zkas_db_set(&consensus_mint_v1_bincode[..])?;
-    zkas_db_set(&consensus_burn_v1_bincode[..])?;
-    zkas_db_set(&consensus_proposal_v1_bincode[..])?;
-
-    // Set up a database tree to hold Merkle roots of all staked coins
-    // k=MerkleNode, v=[]
-    if db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE).is_err() {
-        db_init(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
-    }
-
-    // Set up a database tree to hold all staked coins ever seen
-    // k=Coin, v=[]
-    if db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE).is_err() {
-        db_init(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
-    }
-
-    // Set up a database tree to hold nullifiers of all spent coins
-    // k=Nullifier, v=[]
-    if db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE).is_err() {
-        db_init(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
-    }
-
-    // Set up a database tree to hold Merkle roots of all unstaked coins
-    // k=MerkleNode, v=[]
-    if db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE).is_err() {
-        db_init(cid, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?;
-    }
-
-    // Set up a database tree to hold all unstaked coins ever seen
-    // k=Coin, v=[]
-    if db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE).is_err() {
-        db_init(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
-    }
-
-    // Set up a database tree for arbitrary data
-    let info_db = match db_lookup(cid, CONSENSUS_CONTRACT_INFO_TREE) {
-        Ok(v) => v,
-        Err(_) => {
-            let info_db = db_init(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
-
-            // Create the Merkle tree for staked and unstaked coins.
-            // We can simply reuse the same empty tree twice.
-            let coin_tree = MerkleTree::new(100);
-            let mut coin_tree_data = vec![];
-
-            coin_tree_data.write_u32(0)?;
-            coin_tree.encode(&mut coin_tree_data)?;
-
-            db_set(info_db, CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE, &coin_tree_data)?;
-            db_set(info_db, CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE, &coin_tree_data)?;
-            info_db
-        }
-    };
-
-    // Update db version
-    db_set(info_db, CONSENSUS_CONTRACT_DB_VERSION, &serialize(&env!("CARGO_PKG_VERSION")))?;
-
-    Ok(())
-}
-
-/// This function is used by the wasm VM's host to fetch the necessary metadata
-/// for verifying signatures and zk proofs. The payload given here are all the
-/// contract calls in the transaction.
-fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
-    let (call_idx, calls): (u32, Vec<DarkLeaf<ContractCall>>) = deserialize(ix)?;
-    if call_idx >= calls.len() as u32 {
-        msg!("Error: call_idx >= calls.len()");
-        return Err(ContractError::Internal)
-    }
-
-    match ConsensusFunction::try_from(calls[call_idx as usize].data.data[0])? {
-        ConsensusFunction::GenesisStakeV1 => {
-            // We pass everything into the correct function, and it will return
-            // the metadata for us, which we can then copy into the host with
-            // the `set_return_data` function. On the host, this metadata will
-            // be used to do external verification (zk proofs, and signatures).
-            let metadata = consensus_genesis_stake_get_metadata_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&metadata)?)
-        }
-        ConsensusFunction::StakeV1 => {
-            let metadata = consensus_stake_get_metadata_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&metadata)?)
-        }
-        ConsensusFunction::ProposalV1 => {
-            let metadata = consensus_proposal_get_metadata_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&metadata)?)
-        }
-        ConsensusFunction::UnstakeRequestV1 => {
-            let metadata = consensus_unstake_request_get_metadata_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&metadata)?)
-        }
-        ConsensusFunction::UnstakeV1 => {
-            let metadata = consensus_unstake_get_metadata_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&metadata)?)
-        }
-    }
-}
-
-/// This function verifies a state transition and produces a state update
-/// if everything is successful. This step should happen **after** the host
-/// has successfully verified the metadata from `get_metadata()`.
-fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
-    let (call_idx, calls): (u32, Vec<DarkLeaf<ContractCall>>) = deserialize(ix)?;
-    if call_idx >= calls.len() as u32 {
-        msg!("Error: call_idx >= calls.len()");
-        return Err(ContractError::Internal)
-    }
-
-    match ConsensusFunction::try_from(calls[call_idx as usize].data.data[0])? {
-        ConsensusFunction::GenesisStakeV1 => {
-            // Again, we pass everything into the correct function.
-            // If it executes successfully, we'll get a state update
-            // which we can copy into the host using `set_return_data`.
-            // This update can then be written with `process_update()`
-            // if everything is in order.
-            let update_data = consensus_genesis_stake_process_instruction_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&update_data)?)
-        }
-        ConsensusFunction::StakeV1 => {
-            let update_data = consensus_stake_process_instruction_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&update_data)?)
-        }
-        ConsensusFunction::ProposalV1 => {
-            let update_data = consensus_proposal_process_instruction_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&update_data)?)
-        }
-        ConsensusFunction::UnstakeRequestV1 => {
-            let update_data =
-                consensus_unstake_request_process_instruction_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&update_data)?)
-        }
-        ConsensusFunction::UnstakeV1 => {
-            let update_data = consensus_unstake_process_instruction_v1(cid, call_idx, calls)?;
-            Ok(set_return_data(&update_data)?)
-        }
-    }
-}
-
-/// This function attempts to write a given state update provided the previous steps
-/// of the contract call execution all were successful. It's the last in line, and
-/// assumes that the transaction/call was successful. The payload given to the function
-/// is the update data retrieved from `process_instruction()`.
-fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
-    match ConsensusFunction::try_from(update_data[0])? {
-        ConsensusFunction::GenesisStakeV1 => {
-            let update: ConsensusGenesisStakeUpdateV1 = deserialize(&update_data[1..])?;
-            Ok(consensus_genesis_stake_process_update_v1(cid, update)?)
-        }
-        ConsensusFunction::StakeV1 => {
-            let update: ConsensusStakeUpdateV1 = deserialize(&update_data[1..])?;
-            Ok(consensus_stake_process_update_v1(cid, update)?)
-        }
-        ConsensusFunction::ProposalV1 => {
-            let update: ConsensusProposalUpdateV1 = deserialize(&update_data[1..])?;
-            Ok(consensus_proposal_process_update_v1(cid, update)?)
-        }
-        ConsensusFunction::UnstakeRequestV1 => {
-            let update: ConsensusProposalUpdateV1 = deserialize(&update_data[1..])?;
-            Ok(consensus_unstake_request_process_update_v1(cid, update)?)
-        }
-        ConsensusFunction::UnstakeV1 => {
-            let update: ConsensusUnstakeUpdateV1 = deserialize(&update_data[1..])?;
-            Ok(consensus_unstake_process_update_v1(cid, update)?)
-        }
-    }
-}

+ 0 - 164
src/contract/consensus/src/entrypoint/genesis_stake_v1.rs

@@ -1,164 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_money_contract::{
-    error::MoneyError, CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
-    CONSENSUS_CONTRACT_STAKED_COIN_LATEST_COIN_ROOT, CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE,
-    CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE,
-    CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
-};
-use darkfi_sdk::{
-    crypto::{pasta_prelude::*, pedersen_commitment_u64, ContractId, MerkleNode, DARK_TOKEN_ID},
-    dark_tree::DarkLeaf,
-    db::{db_contains_key, db_lookup, db_set},
-    error::{ContractError, ContractResult},
-    merkle_add, msg,
-    pasta::pallas,
-    util::get_verifying_slot,
-    ContractCall,
-};
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
-
-use crate::{
-    model::{ConsensusGenesisStakeParamsV1, ConsensusGenesisStakeUpdateV1},
-    ConsensusFunction,
-};
-
-/// `get_metadata` function for `Consensus::GenesisStakeV1`
-///
-/// Here we gather the signature pubkey from the clear input in order
-/// to verify the transaction, and we extract the necessary public inputs
-/// that go into the `ConsensusMint_V1` proof verification.
-pub(crate) fn consensus_genesis_stake_get_metadata_v1(
-    _cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: ConsensusGenesisStakeParamsV1 = deserialize(&self_.data[1..])?;
-
-    // Public inputs for the ZK proofs we have to verify
-    let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
-    // Public keys for the transaction signatures we have to verify
-    let signature_pubkeys = vec![params.input.signature_public];
-
-    // Genesis stake only happens on epoch 0
-    let epoch = pallas::Base::ZERO;
-
-    // Grab the pedersen commitment from the anonymous output
-    let value_coords = params.output.value_commit.to_affine().coordinates().unwrap();
-
-    zk_public_inputs.push((
-        CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1.to_string(),
-        vec![epoch, params.output.coin.inner(), *value_coords.x(), *value_coords.y()],
-    ));
-
-    // Serialize everything gathered and return it
-    let mut metadata = vec![];
-    zk_public_inputs.encode(&mut metadata)?;
-    signature_pubkeys.encode(&mut metadata)?;
-
-    Ok(metadata)
-}
-
-/// `process_instruction` function for `Consensus::GenesisStakeV1`
-pub(crate) fn consensus_genesis_stake_process_instruction_v1(
-    cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: ConsensusGenesisStakeParamsV1 = deserialize(&self_.data[1..])?;
-
-    // Verify this contract call is verified on the genesis slot (0).
-    let verifying_slot = get_verifying_slot();
-    if verifying_slot != 0 {
-        msg!(
-            "[ConsensusGenesisStakeV1] Error: Call is executed for slot {}, not genesis",
-            verifying_slot
-        );
-        return Err(MoneyError::GenesisCallNonGenesisSlot.into())
-    }
-
-    // Only DARK_TOKEN_ID can be minted and staked on genesis slot.
-    if params.input.token_id != *DARK_TOKEN_ID {
-        msg!("[ConsensusGenesisStakeV1] Error: Clear input used non-native token");
-        return Err(MoneyError::TransferClearInputNonNativeToken.into())
-    }
-
-    // Access the necessary databases where there is information to
-    // validate this state transition.
-    let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
-    let unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
-
-    // Check that the coin from the output hasn't existed before.
-    let coin = serialize(&params.output.coin);
-    if db_contains_key(staked_coins_db, &coin)? {
-        msg!("[ConsensusGenesisStakeV1] Error: Output coin was already seen in the set of staked coins");
-        return Err(MoneyError::DuplicateCoin.into())
-    }
-
-    // Check that the coin from the output hasn't existed before in unstake set.
-    if db_contains_key(unstaked_coins_db, &coin)? {
-        msg!("[ConsensusGenesisStakeV1] Error: Output coin was already seen in the set of unstaked coins");
-        return Err(MoneyError::DuplicateCoin.into())
-    }
-
-    // Verify that the value commitments match. In here we just confirm
-    // that the clear input and the anon output have the same commitment.
-    if pedersen_commitment_u64(params.input.value, params.input.value_blind) !=
-        params.output.value_commit
-    {
-        msg!("[ConsensusGenesisStakeV1] Error: Value commitment mismatch");
-        return Err(MoneyError::ValueMismatch.into())
-    }
-
-    // Create a state update.
-    let update = ConsensusGenesisStakeUpdateV1 { coin: params.output.coin };
-    let mut update_data = vec![];
-    update_data.write_u8(ConsensusFunction::StakeV1 as u8)?;
-    update.encode(&mut update_data)?;
-
-    Ok(update_data)
-}
-
-/// `process_update` function for `Consensus::GenesisStakeV1`
-pub(crate) fn consensus_genesis_stake_process_update_v1(
-    cid: ContractId,
-    update: ConsensusGenesisStakeUpdateV1,
-) -> ContractResult {
-    // Grab all necessary db handles for where we want to write
-    let info_db = db_lookup(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
-    let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
-    let staked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
-
-    msg!("[ConsensusGenesisStakeV1] Adding new coin to the set");
-    db_set(staked_coins_db, &serialize(&update.coin), &[])?;
-
-    msg!("[ConsensusGenesisStakeV1] Adding new coin to the Merkle tree");
-    let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
-    merkle_add(
-        info_db,
-        staked_coin_roots_db,
-        CONSENSUS_CONTRACT_STAKED_COIN_LATEST_COIN_ROOT,
-        CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE,
-        &coins,
-    )?;
-
-    Ok(())
-}

+ 0 - 249
src/contract/consensus/src/entrypoint/proposal_v1.rs

@@ -1,249 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_money_contract::{
-    error::MoneyError, CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
-    CONSENSUS_CONTRACT_STAKED_COINS_TREE, CONSENSUS_CONTRACT_STAKED_COIN_LATEST_COIN_ROOT,
-    CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE,
-    CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1,
-};
-use darkfi_sdk::{
-    blockchain::Slot,
-    crypto::{pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, ContractId, MerkleNode},
-    dark_tree::DarkLeaf,
-    db::{db_contains_key, db_lookup, db_set},
-    error::{ContractError, ContractResult},
-    merkle_add, msg,
-    pasta::{group::ff::FromUniformBytes, pallas},
-    util::{get_slot, get_verifying_slot, get_verifying_slot_epoch},
-    ContractCall,
-};
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
-
-use crate::{
-    error::ConsensusError,
-    model::{
-        ConsensusProposalParamsV1, ConsensusProposalUpdateV1, GRACE_PERIOD, HEADSTART,
-        MU_RHO_PREFIX, MU_Y_PREFIX, REWARD, REWARD_PALLAS,
-    },
-    ConsensusFunction,
-};
-
-/// `get_metadata` function for `Consensus::ProposalV1`
-pub(crate) fn consensus_proposal_get_metadata_v1(
-    _cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: ConsensusProposalParamsV1 = deserialize(&self_.data[1..])?;
-
-    // Public inputs for the ZK proofs we have to verify
-    let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
-    // Public keys for the transaction signatures we have to verify.
-    // The transaction should be signed with the same key that is used for
-    // the VRF proof, and also constrained in ZK by enforcing its derivation.
-    let signature_pubkeys = vec![params.input.signature_public];
-
-    // Grab the public key coordinates for the burnt coin
-    let (pub_x, pub_y) = &params.input.signature_public.xy();
-
-    // Grab the pedersen commitment for the burnt value
-    let input_value_coords = &params.input.value_commit.to_affine().coordinates().unwrap();
-
-    // Grab the pedersen commitment for the minted value
-    let output_value_coords = &params.output.value_commit.to_affine().coordinates().unwrap();
-
-    // Grab the slot to validate consensus params against
-    let v_slot = get_verifying_slot();
-    let Some(slot) = get_slot(v_slot)? else {
-        msg!("[ConsensusProposalV1] Error: Missing slot {} from db", v_slot);
-        return Err(ConsensusError::ProposalMissingSlot.into())
-    };
-    let slot: Slot = deserialize(&slot)?;
-    let slot_fp = pallas::Base::from(slot.id);
-
-    // Verify proposal extends a known fork
-    if !slot.previous.last_hashes.contains(&params.fork_hash) {
-        msg!("[ConsensusProposalV1] Error: Proposal extends unknown fork {}", params.fork_hash);
-        return Err(ConsensusError::ProposalExtendsUnknownFork.into())
-    }
-
-    // Verify sequence is correct
-    if !slot.previous.second_to_last_hashes.contains(&params.fork_previous_hash) {
-        let fork_prev = &params.fork_previous_hash;
-        msg!("[ConsensusProposalV1] Error: Proposal extends unknown fork {}", fork_prev);
-        return Err(ConsensusError::ProposalExtendsUnknownFork.into())
-    }
-
-    // Construct VRF input
-    let mut vrf_input = Vec::with_capacity(32 + blake3::OUT_LEN + 32);
-    vrf_input.extend_from_slice(&slot.last_nonce.to_repr());
-    vrf_input.extend_from_slice(params.fork_previous_hash.as_bytes());
-    vrf_input.extend_from_slice(&slot_fp.to_repr());
-
-    // Verify VRF proof
-    if !params.vrf_proof.verify(params.input.signature_public, &vrf_input) {
-        msg!("[ConsensusProposalV1] Error: VRF proof couldn't be verified");
-        return Err(ConsensusError::ProposalErroneousVrfProof.into())
-    }
-
-    // Construct eta
-    let mut eta = [0u8; 64];
-    eta[..blake3::OUT_LEN].copy_from_slice(params.vrf_proof.hash_output().as_bytes());
-    let eta = pallas::Base::from_uniform_bytes(&eta);
-
-    // Calculate election seeds
-    let mu_y = poseidon_hash([MU_Y_PREFIX, eta, slot_fp]);
-    let mu_rho = poseidon_hash([MU_RHO_PREFIX, eta, slot_fp]);
-
-    // Grab sigmas from slot
-    let (sigma1, sigma2) = (slot.pid.sigma1, slot.pid.sigma2);
-
-    zk_public_inputs.push((
-        CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1.to_string(),
-        vec![
-            params.input.nullifier.inner(),
-            pallas::Base::from(params.input.epoch),
-            *pub_x,
-            *pub_y,
-            params.input.merkle_root.inner(),
-            *input_value_coords.x(),
-            *input_value_coords.y(),
-            REWARD_PALLAS,
-            *output_value_coords.x(),
-            *output_value_coords.y(),
-            params.output.coin.inner(),
-            mu_y,
-            params.y,
-            mu_rho,
-            params.rho,
-            sigma1,
-            sigma2,
-            HEADSTART,
-        ],
-    ));
-
-    // Serialize everything gathered and return it
-    let mut metadata = vec![];
-    zk_public_inputs.encode(&mut metadata)?;
-    signature_pubkeys.encode(&mut metadata)?;
-
-    Ok(metadata)
-}
-
-/// `process_instruction` function for `Consensus::ProposalV1`
-pub(crate) fn consensus_proposal_process_instruction_v1(
-    cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: ConsensusProposalParamsV1 = deserialize(&self_.data[1..])?;
-    let input = &params.input;
-    let output = &params.output;
-
-    // Access the necessary databases where there is information to
-    // validate this state transition.
-    let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
-    let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
-    let staked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
-
-    // ===================================
-    // Perform the actual state transition
-    // ===================================
-
-    msg!("[ConsensusProposalV1] Validating anonymous input");
-
-    // The coin has passed through the grace period and is allowed to propose.
-    // Important to note is that the epoch has to be enforced through ZK. The
-    // only time when the epoch of the burned coin can be zero is when there
-    // was a previous winning proposal, or the coin was minted at genesis.
-    if input.epoch != 0 && get_verifying_slot_epoch() - input.epoch <= GRACE_PERIOD {
-        msg!("[ConsensusProposalV1] Error: Coin is not allowed to make proposals yet");
-        return Err(ConsensusError::CoinStillInGracePeriod.into())
-    }
-
-    // The Merkle root is used to know whether this is a coin that
-    // existed in a previous state.
-    if !db_contains_key(staked_coin_roots_db, &serialize(&input.merkle_root))? {
-        msg!("[ConsensusProposalV1] Error: Merkle root not found in previous state");
-        return Err(MoneyError::TransferMerkleRootNotFound.into())
-    }
-
-    // The nullifier should not already exist. It is the double-spend protection.
-    if db_contains_key(nullifiers_db, &serialize(&input.nullifier))? {
-        msg!("[ConsensusProposalV1] Error: Duplicate nullifier found");
-        return Err(MoneyError::DuplicateNullifier.into())
-    }
-
-    // Verify value commits match between burnt and mint inputs.
-    // Here we check that input+reward == output
-    let mut valcom_total = pallas::Point::identity();
-    valcom_total += input.value_commit;
-    valcom_total += pedersen_commitment_u64(REWARD, params.reward_blind);
-    valcom_total -= output.value_commit;
-    if valcom_total != pallas::Point::identity() {
-        msg!("[ConsensusProposalV1] Error: Value commitments do not result in identity");
-        return Err(MoneyError::ValueMismatch.into())
-    }
-
-    // Newly created coin for this call is in the output. Here we check that
-    // it hasn't existed before.
-    if db_contains_key(staked_coins_db, &serialize(&output.coin))? {
-        msg!("[ConsensusProposalV1] Error: Duplicate coin found in output");
-        return Err(MoneyError::DuplicateCoin.into())
-    }
-
-    // At this point the state transition has passed, so we create a state update
-    let update = ConsensusProposalUpdateV1 { nullifier: input.nullifier, coin: output.coin };
-    let mut update_data = vec![];
-    update_data.write_u8(ConsensusFunction::ProposalV1 as u8)?;
-    update.encode(&mut update_data)?;
-    Ok(update_data)
-}
-
-/// `process_update` function for `Consensus::ProposalV1`
-pub(crate) fn consensus_proposal_process_update_v1(
-    cid: ContractId,
-    update: ConsensusProposalUpdateV1,
-) -> ContractResult {
-    // Grab all necessary db handles for where we want to write
-    let info_db = db_lookup(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
-    let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
-    let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
-    let staked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
-
-    msg!("[ConsensusProposalV1] Adding new nullifier to the set");
-    db_set(nullifiers_db, &serialize(&update.nullifier), &[])?;
-
-    msg!("[ConsensusProposalV1] Adding new coin to the staked coin set");
-    db_set(staked_coins_db, &serialize(&update.coin), &[])?;
-
-    msg!("[ConsensusProposalV1] Adding new coin to the Merkle tree");
-    let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
-    merkle_add(
-        info_db,
-        staked_coin_roots_db,
-        CONSENSUS_CONTRACT_STAKED_COIN_LATEST_COIN_ROOT,
-        CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE,
-        &coins,
-    )?;
-
-    Ok(())
-}

+ 0 - 202
src/contract/consensus/src/entrypoint/stake_v1.rs

@@ -1,202 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_money_contract::{
-    error::MoneyError,
-    model::{ConsensusStakeParamsV1, ConsensusStakeUpdateV1, MoneyStakeParamsV1},
-    MoneyFunction, CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
-    CONSENSUS_CONTRACT_STAKED_COIN_LATEST_COIN_ROOT, CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE,
-    CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE,
-    CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1, MONEY_CONTRACT_COIN_ROOTS_TREE,
-    MONEY_CONTRACT_NULLIFIERS_TREE,
-};
-use darkfi_sdk::{
-    crypto::{pasta_prelude::*, ContractId, MerkleNode, PublicKey, MONEY_CONTRACT_ID},
-    dark_tree::DarkLeaf,
-    db::{db_contains_key, db_lookup, db_set},
-    error::{ContractError, ContractResult},
-    merkle_add, msg,
-    pasta::pallas,
-    util::get_verifying_slot_epoch,
-    ContractCall,
-};
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
-
-use crate::ConsensusFunction;
-
-/// `get_metadata` function for `Consensus::StakeV1`
-pub(crate) fn consensus_stake_get_metadata_v1(
-    _cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: ConsensusStakeParamsV1 = deserialize(&self_.data[1..])?;
-
-    // Public inputs for the ZK proofs we have to verify
-    let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
-    // We are already verifying this input's signature through `Money::Stake`,
-    // so it's redundant to verify it here again. However it's important to
-    // compare it with the previous call when we do the state transition to
-    // ensure they're the same.
-    let signature_pubkeys: Vec<PublicKey> = vec![];
-
-    // Grab the minting epoch of the verifying slot
-    let epoch = get_verifying_slot_epoch();
-
-    // Grab the pedersen commitment from the anonymous output
-    let output = &params.output;
-    let value_coords = output.value_commit.to_affine().coordinates().unwrap();
-
-    zk_public_inputs.push((
-        CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1.to_string(),
-        vec![epoch.into(), output.coin.inner(), *value_coords.x(), *value_coords.y()],
-    ));
-
-    // Serialize everything gathered and return it
-    let mut metadata = vec![];
-    zk_public_inputs.encode(&mut metadata)?;
-    signature_pubkeys.encode(&mut metadata)?;
-
-    Ok(metadata)
-}
-
-/// `process_instruction` function for `Consensus::StakeV1`
-pub(crate) fn consensus_stake_process_instruction_v1(
-    cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize];
-    let params: ConsensusStakeParamsV1 = deserialize(&self_.data.data[1..])?;
-
-    // Check child call is money contract
-    if call_idx == 0 {
-        msg!("[ConsensusStakeV1] Error: child_call_idx will be out of bounds");
-        return Err(MoneyError::CallIdxOutOfBounds.into())
-    }
-
-    let child_call_indexes = &self_.children_indexes;
-    if child_call_indexes.len() != 1 {
-        msg!("[ConsensusStakeV1] Error: child_call_idx is missing");
-        return Err(MoneyError::StakeChildCallNotMoneyContract.into())
-    }
-    let child_call_idx = child_call_indexes[0];
-
-    // Verify child call corresponds to Money::StakeV1
-    let child = &calls[child_call_idx].data;
-    if child.contract_id.inner() != MONEY_CONTRACT_ID.inner() {
-        msg!("[ConsensusStakeV1] Error: Child contract call is not money contract");
-        return Err(MoneyError::StakeChildCallNotMoneyContract.into())
-    }
-
-    if child.data[0] != MoneyFunction::StakeV1 as u8 {
-        msg!("[ConsensusStakeV1] Error: Child call function mismatch");
-        return Err(MoneyError::ChildCallFunctionMismatch.into())
-    }
-
-    // Verify that the child call's input is the same as this one's
-    let child_params: MoneyStakeParamsV1 = deserialize(&child.data[1..])?;
-    let child_input = &child_params.input;
-    if child_input != &params.input {
-        msg!("[ConsensusStakeV1] Error: Child call input mismatch");
-        return Err(MoneyError::ChildCallInputMismatch.into())
-    }
-
-    // Access the necessary databases where there is information to
-    // validate this state transition.
-    let consensus_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
-    let consensus_unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
-    let money_nullifiers_db = db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_NULLIFIERS_TREE)?;
-    let money_coin_roots_db = db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
-
-    // ===================================
-    // Perform the actual state transition
-    // ===================================
-
-    msg!("[ConsensusStakeV1] Validating anonymous output");
-    let input = &params.input;
-    let output = &params.output;
-
-    // Verify value commitments match
-    if output.value_commit != input.value_commit {
-        msg!("[ConsensusStakeV1] Error: Value commitments do not match");
-        return Err(MoneyError::ValueMismatch.into())
-    }
-
-    // The Merkle root is used to know whether this is a coin that
-    // existed in a previous state.
-    if !db_contains_key(money_coin_roots_db, &serialize(&input.merkle_root))? {
-        msg!("[ConsensusStakeV1] Error: Merkle root not found in previous state");
-        return Err(MoneyError::TransferMerkleRootNotFound.into())
-    }
-
-    // The nullifiers should not already exist. It is the double-mint protection.
-    if !db_contains_key(money_nullifiers_db, &serialize(&input.nullifier))? {
-        msg!("[ConsensusStakeV1] Error: Missing nullifier");
-        return Err(MoneyError::StakeMissingNullifier.into())
-    }
-
-    // Newly created coin for this call is in the output. Here we gather it,
-    // and we also check that it hasn't existed before.
-    let coin = serialize(&output.coin);
-    if db_contains_key(consensus_coins_db, &coin)? {
-        msg!("[ConsensusStakeV1] Error: Duplicate coin found in output");
-        return Err(MoneyError::DuplicateCoin.into())
-    }
-
-    // Check that the coin hasn't existed before in unstake set.
-    if db_contains_key(consensus_unstaked_coins_db, &coin)? {
-        msg!("[ConsensusStakeV1] Error: Unstaked coin found in output");
-        return Err(MoneyError::DuplicateCoin.into())
-    }
-
-    // Create a state update.
-    let update = ConsensusStakeUpdateV1 { coin: output.coin };
-    let mut update_data = vec![];
-    update_data.write_u8(ConsensusFunction::StakeV1 as u8)?;
-    update.encode(&mut update_data)?;
-
-    Ok(update_data)
-}
-
-/// `process_update` function for `Consensus::StakeV1`
-pub(crate) fn consensus_stake_process_update_v1(
-    cid: ContractId,
-    update: ConsensusStakeUpdateV1,
-) -> ContractResult {
-    // Grab all necessary db handles for where we want to write
-    let info_db = db_lookup(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
-    let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
-    let staked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
-
-    msg!("[ConsensusStakeV1] Adding new coin to the set");
-    db_set(staked_coins_db, &serialize(&update.coin), &[])?;
-
-    msg!("[ConsensusStakeV1] Adding new coin to the Merkle tree");
-    let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
-    merkle_add(
-        info_db,
-        staked_coin_roots_db,
-        CONSENSUS_CONTRACT_STAKED_COIN_LATEST_COIN_ROOT,
-        CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE,
-        &coins,
-    )?;
-
-    Ok(())
-}

+ 0 - 193
src/contract/consensus/src/entrypoint/unstake_request_v1.rs

@@ -1,193 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_money_contract::{
-    error::MoneyError, model::ConsensusUnstakeReqParamsV1, CONSENSUS_CONTRACT_INFO_TREE,
-    CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE,
-    CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_LATEST_COIN_ROOT,
-    CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE,
-    CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
-};
-use darkfi_sdk::{
-    crypto::{pasta_prelude::*, ContractId, MerkleNode},
-    dark_tree::DarkLeaf,
-    db::{db_contains_key, db_lookup, db_set},
-    error::{ContractError, ContractResult},
-    merkle_add, msg,
-    pasta::pallas,
-    util::get_verifying_slot_epoch,
-    ContractCall,
-};
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
-
-use crate::{
-    error::ConsensusError,
-    model::{ConsensusProposalUpdateV1, GRACE_PERIOD},
-    ConsensusFunction,
-};
-
-/// `get_metadata` function for `Consensus::UnstakeRequestV1`
-pub(crate) fn consensus_unstake_request_get_metadata_v1(
-    _cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: ConsensusUnstakeReqParamsV1 = deserialize(&self_.data[1..])?;
-    let input = &params.input;
-    let output = &params.output;
-
-    // Public inputs for the ZK proofs we have to verify
-    let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
-    // Public keys for the transaction signatures we have to verify
-    let signature_pubkeys = vec![input.signature_public];
-
-    // Grab the pedersen commitments and signature pubkeys from the
-    // anonymous input
-    let value_coords = input.value_commit.to_affine().coordinates().unwrap();
-    let (sig_x, sig_y) = input.signature_public.xy();
-
-    // It is very important that these are in the same order as the
-    // `constrain_instance` calls in the zkas code.
-    // Otherwise verification will fail.
-    zk_public_inputs.push((
-        CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1.to_string(),
-        vec![
-            input.nullifier.inner(),
-            input.epoch.into(),
-            sig_x,
-            sig_y,
-            input.merkle_root.inner(),
-            *value_coords.x(),
-            *value_coords.y(),
-        ],
-    ));
-
-    // Grab the minting epoch of the verifying slot
-    let epoch = get_verifying_slot_epoch();
-
-    // Grab the pedersen commitment from the anonymous output
-    let value_coords = output.value_commit.to_affine().coordinates().unwrap();
-
-    zk_public_inputs.push((
-        CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1.to_string(),
-        vec![epoch.into(), output.coin.inner(), *value_coords.x(), *value_coords.y()],
-    ));
-
-    // Serialize everything gathered and return it
-    let mut metadata = vec![];
-    zk_public_inputs.encode(&mut metadata)?;
-    signature_pubkeys.encode(&mut metadata)?;
-
-    Ok(metadata)
-}
-
-/// `process_instruction` function for `Consensus::UnstakeRequestV1`
-pub(crate) fn consensus_unstake_request_process_instruction_v1(
-    cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: ConsensusUnstakeReqParamsV1 = deserialize(&self_.data[1..])?;
-    let input = &params.input;
-    let output = &params.output;
-
-    // Access the necessary databases where there is information to
-    // validate this state transition.
-    let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
-    let unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
-    let staked_coins_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
-
-    // ===================================
-    // Perform the actual state transition
-    // ===================================
-
-    msg!("[ConsensusUnstakeRequestV1] Validating anonymous input");
-
-    // The coin has passed through the grace period and is allowed to request unstake.
-    if input.epoch != 0 && get_verifying_slot_epoch() - input.epoch <= GRACE_PERIOD {
-        msg!("[ConsensusUnstakeRequestV1] Error: Coin is not allowed to request unstake yet");
-        return Err(ConsensusError::CoinStillInGracePeriod.into())
-    }
-
-    // The Merkle root is used to know whether this is a coin that
-    // existed in a previous state.
-    if !db_contains_key(staked_coins_roots_db, &serialize(&input.merkle_root))? {
-        msg!("[ConsensusUnstakeRequestV1] Error: Merkle root not found in previous state");
-        return Err(MoneyError::TransferMerkleRootNotFound.into())
-    }
-
-    // The nullifiers should not already exist. It is the double-spend protection.
-    if db_contains_key(nullifiers_db, &serialize(&input.nullifier))? {
-        msg!("[ConsensusUnstakeRequestV1] Error: Duplicate nullifier found");
-        return Err(MoneyError::DuplicateNullifier.into())
-    }
-
-    msg!("[ConsensusUnstakeRequestV1] Validating anonymous output");
-
-    // Verify value commits match
-    if output.value_commit != input.value_commit {
-        msg!("[ConsensusUnstakeRequestV1] Error: Value commitments do not match");
-        return Err(MoneyError::ValueMismatch.into())
-    }
-
-    // Newly created coin for this call is in the output. Here we gather it,
-    // and we also check that it hasn't existed before.
-    if db_contains_key(unstaked_coins_db, &serialize(&output.coin))? {
-        msg!("[ConsensusUnstakeRequestV1] Error: Duplicate coin found in output");
-        return Err(MoneyError::DuplicateCoin.into())
-    }
-
-    // At this point the state transition has passed, so we create a state update
-    let update = ConsensusProposalUpdateV1 { nullifier: input.nullifier, coin: output.coin };
-    let mut update_data = vec![];
-    update_data.write_u8(ConsensusFunction::UnstakeRequestV1 as u8)?;
-    update.encode(&mut update_data)?;
-    Ok(update_data)
-}
-
-/// `process_update` function for `Consensus::UnstakeRequestV1`
-pub(crate) fn consensus_unstake_request_process_update_v1(
-    cid: ContractId,
-    update: ConsensusProposalUpdateV1,
-) -> ContractResult {
-    // Grab all necessary db handles for where we want to write
-    let info_db = db_lookup(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
-    let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
-    let unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
-    let unstaked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?;
-
-    msg!("[ConsensusUnstakeRequestV1] Adding new nullifier to the set");
-    db_set(nullifiers_db, &serialize(&update.nullifier), &[])?;
-
-    msg!("[ConsensusUnstakeRequestV1] Adding new coin to the unstaked coins set");
-    db_set(unstaked_coins_db, &serialize(&update.coin), &[])?;
-
-    msg!("[ConsensusUnstakeRequestV1] Adding new coin to the unstaked coins Merkle tree");
-    let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
-    merkle_add(
-        info_db,
-        unstaked_coin_roots_db,
-        CONSENSUS_CONTRACT_UNSTAKED_COIN_LATEST_COIN_ROOT,
-        CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE,
-        &coins,
-    )?;
-
-    Ok(())
-}

+ 0 - 173
src/contract/consensus/src/entrypoint/unstake_v1.rs

@@ -1,173 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_money_contract::{
-    error::MoneyError,
-    model::{ConsensusUnstakeParamsV1, ConsensusUnstakeUpdateV1, MoneyUnstakeParamsV1},
-    MoneyFunction, CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE,
-    CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1,
-};
-use darkfi_sdk::{
-    crypto::{pasta_prelude::*, ContractId, MONEY_CONTRACT_ID},
-    dark_tree::DarkLeaf,
-    db::{db_contains_key, db_lookup, db_set},
-    error::{ContractError, ContractResult},
-    msg,
-    pasta::pallas,
-    util::get_verifying_slot_epoch,
-    ContractCall,
-};
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
-
-use crate::{error::ConsensusError, model::GRACE_PERIOD, ConsensusFunction};
-
-/// `get_metadata` function for `Consensus::UnstakeV1`
-pub(crate) fn consensus_unstake_get_metadata_v1(
-    _cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: ConsensusUnstakeParamsV1 = deserialize(&self_.data[1..])?;
-    let input = &params.input;
-
-    // Public inputs for the ZK proofs we have to verify
-    let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
-    // Public keys for the transaction signatures we have to verify
-    let signature_pubkeys = vec![input.signature_public];
-
-    // Grab the pedersen commitment and signature pubkey coordinates from the
-    // anonymous input
-    let value_coords = input.value_commit.to_affine().coordinates().unwrap();
-    let (sig_x, sig_y) = input.signature_public.xy();
-
-    // It is very important that these are in the same order as the
-    // `constrain_instance` calls in the zkas code.
-    // Otherwise verification will fail.
-    zk_public_inputs.push((
-        CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1.to_string(),
-        vec![
-            input.nullifier.inner(),
-            pallas::Base::from(input.epoch),
-            sig_x,
-            sig_y,
-            input.merkle_root.inner(),
-            *value_coords.x(),
-            *value_coords.y(),
-        ],
-    ));
-
-    // Serialize everything gathered and return it
-    let mut metadata = vec![];
-    zk_public_inputs.encode(&mut metadata)?;
-    signature_pubkeys.encode(&mut metadata)?;
-    Ok(metadata)
-}
-
-/// `process_instruction` function for `Consensus::UnstakeV1`
-pub(crate) fn consensus_unstake_process_instruction_v1(
-    cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize];
-    let params: ConsensusUnstakeParamsV1 = deserialize(&self_.data.data[1..])?;
-    let input = &params.input;
-
-    // Access the necessary databases where there is information to
-    // validate this state transition.
-    let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
-    let unstaked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?;
-
-    // ===================================
-    // Perform the actual state transition
-    // ===================================
-
-    // Check parent call is money contract
-    let parent_call_idx = self_.parent_index;
-    if parent_call_idx.is_none() {
-        msg!("[ConsensusUnstakeV1] Error: parent_call_idx is missing");
-        return Err(MoneyError::UnstakeParentCallNotMoneyContract.into())
-    }
-    let parent_call_idx = parent_call_idx.unwrap();
-
-    if parent_call_idx >= calls.len() {
-        msg!("[ConsensusUnstakeV1] Error: parent_call_idx out of bounds");
-        return Err(MoneyError::CallIdxOutOfBounds.into())
-    }
-
-    let parent = &calls[parent_call_idx].data;
-    if parent.contract_id.inner() != MONEY_CONTRACT_ID.inner() {
-        msg!("[ConsensusUnstakeV1] Error: Parent contract call is not money contract");
-        return Err(MoneyError::UnstakeParentCallNotMoneyContract.into())
-    }
-
-    // Verify parent call corresponds to Money::UnstakeV1
-    if parent.data[0] != MoneyFunction::UnstakeV1 as u8 {
-        msg!("[ConsensusUnstakeV1] Error: Parent call function mismatch");
-        return Err(MoneyError::ParentCallFunctionMismatch.into())
-    }
-
-    // Verify parent call input is the same as this calls input
-    let parent_params: MoneyUnstakeParamsV1 = deserialize(&parent.data[1..])?;
-    if input != &parent_params.input {
-        msg!("[ConsensusUnstakeV1] Error: Parent call input mismatch");
-        return Err(MoneyError::ParentCallInputMismatch.into())
-    }
-
-    msg!("[ConsensusUnstakeV1] Validating anonymous input");
-    // The coin has passed through the grace period and is allowed to get unstaked.
-    if get_verifying_slot_epoch() - input.epoch <= GRACE_PERIOD {
-        msg!("[ConsensusUnstakeV1] Error: Coin is not allowed to get unstaked yet");
-        return Err(ConsensusError::CoinStillInGracePeriod.into())
-    }
-
-    // The Merkle root is used to know whether this is an unstaked coin that
-    // existed in a previous state.
-    if !db_contains_key(unstaked_coin_roots_db, &serialize(&input.merkle_root))? {
-        msg!("[ConsensusUnstakeV1] Error: Merkle root not found in previous state");
-        return Err(MoneyError::TransferMerkleRootNotFound.into())
-    }
-
-    // The nullifiers should not already exist. It is the double-spend protection.
-    if db_contains_key(nullifiers_db, &serialize(&input.nullifier))? {
-        msg!("[ConsensusUnstakeV1] Error: Duplicate nullifier found");
-        return Err(MoneyError::DuplicateNullifier.into())
-    }
-
-    // At this point the state transition has passed, so we create a state update
-    let update = ConsensusUnstakeUpdateV1 { nullifier: input.nullifier };
-    let mut update_data = vec![];
-    update_data.write_u8(ConsensusFunction::UnstakeV1 as u8)?;
-    update.encode(&mut update_data)?;
-    Ok(update_data)
-}
-
-/// `process_update` function for `Consensus::UnstakeV1`
-pub(crate) fn consensus_unstake_process_update_v1(
-    cid: ContractId,
-    update: ConsensusUnstakeUpdateV1,
-) -> ContractResult {
-    // Grab all necessary db handles for where we want to write
-    let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
-
-    msg!("[ConsensusUnstakeV1] Adding new nullifier to the set");
-    db_set(nullifiers_db, &serialize(&update.nullifier), &[])?;
-
-    Ok(())
-}

+ 0 - 49
src/contract/consensus/src/error.rs

@@ -1,49 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::error::ContractError;
-
-#[derive(Debug, Clone, thiserror::Error)]
-pub enum ConsensusError {
-    #[error("Missing slot from db")]
-    ProposalMissingSlot,
-
-    #[error("Proposal extends unknown fork")]
-    ProposalExtendsUnknownFork,
-
-    #[error("Eta VRF proof couldn't be verified")]
-    ProposalErroneousVrfProof,
-
-    #[error("Coin is still in grace period")]
-    CoinStillInGracePeriod,
-
-    #[error("Coin doesn't exist in unstake set")]
-    CoinNotInUnstakeSet,
-}
-
-impl From<ConsensusError> for ContractError {
-    fn from(e: ConsensusError) -> Self {
-        match e {
-            ConsensusError::ProposalMissingSlot => Self::Custom(1),
-            ConsensusError::ProposalExtendsUnknownFork => Self::Custom(2),
-            ConsensusError::ProposalErroneousVrfProof => Self::Custom(3),
-            ConsensusError::CoinStillInGracePeriod => Self::Custom(4),
-            ConsensusError::CoinNotInUnstakeSet => Self::Custom(5),
-        }
-    }
-}

+ 0 - 61
src/contract/consensus/src/lib.rs

@@ -1,61 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! Smart contract implementing staking, unstaking and evolving
-//! of consensus tokens.
-
-use darkfi_sdk::error::ContractError;
-
-/// Functions available in the contract
-#[repr(u8)]
-pub enum ConsensusFunction {
-    GenesisStakeV1 = 0x00,
-    StakeV1 = 0x01,
-    ProposalV1 = 0x02,
-    UnstakeRequestV1 = 0x03,
-    UnstakeV1 = 0x04,
-}
-
-impl TryFrom<u8> for ConsensusFunction {
-    type Error = ContractError;
-
-    fn try_from(b: u8) -> core::result::Result<Self, Self::Error> {
-        match b {
-            0x00 => Ok(Self::GenesisStakeV1),
-            0x01 => Ok(Self::StakeV1),
-            0x02 => Ok(Self::ProposalV1),
-            0x03 => Ok(Self::UnstakeRequestV1),
-            0x04 => Ok(Self::UnstakeV1),
-            _ => Err(ContractError::InvalidFunction),
-        }
-    }
-}
-
-/// Internal contract errors
-pub mod error;
-
-/// Call parameters definitions
-pub mod model;
-
-#[cfg(not(feature = "no-entrypoint"))]
-/// WASM entrypoint functions
-pub mod entrypoint;
-
-#[cfg(feature = "client")]
-/// Client API for interaction with this smart contract
-pub mod client;

+ 0 - 138
src/contract/consensus/src/model.rs

@@ -1,138 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_money_contract::model::{ClearInput, Coin, ConsensusInput, ConsensusOutput, Output};
-use darkfi_sdk::{
-    crypto::{ecvrf::VrfProof, Nullifier},
-    pasta::pallas,
-};
-use darkfi_serial::{SerialDecodable, SerialEncodable};
-
-#[cfg(feature = "client")]
-use darkfi_serial::async_trait;
-
-/// Parameters for `Consensus::GenesisStake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusGenesisStakeParams
-pub struct ConsensusGenesisStakeParamsV1 {
-    /// Clear input
-    pub input: ClearInput,
-    /// Anonymous output
-    pub output: ConsensusOutput,
-}
-// ANCHOR_END: ConsensusGenesisStakeParams
-
-/// State update for `Consensus::GenesisStake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusGenesisStakeUpdate
-pub struct ConsensusGenesisStakeUpdateV1 {
-    /// The newly minted coin
-    pub coin: Coin,
-}
-// ANCHOR_END: ConsensusGenesisStakeUpdate
-
-/// Parameters for `Consensus::Proposal`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusProposalParams
-pub struct ConsensusProposalParamsV1 {
-    /// Anonymous input
-    pub input: ConsensusInput,
-    /// Anonymous output
-    pub output: ConsensusOutput,
-    /// Reward value
-    pub reward: u64,
-    /// Revealed blinding factor for reward value
-    pub reward_blind: pallas::Scalar,
-    /// Extending fork last proposal/block hash
-    pub fork_hash: blake3::Hash,
-    /// Extending fork second to last proposal/block hash
-    pub fork_previous_hash: blake3::Hash,
-    /// VRF proof for eta calculation
-    pub vrf_proof: VrfProof,
-    /// Coin y
-    pub y: pallas::Base,
-    /// Lottery rho used
-    pub rho: pallas::Base,
-}
-// ANCHOR_END: ConsensusProposalParams
-
-/// State update for `Consensus::Proposal`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusProposalUpdate
-pub struct ConsensusProposalUpdateV1 {
-    /// Revealed nullifier
-    pub nullifier: Nullifier,
-    /// The newly minted coin
-    pub coin: Coin,
-}
-// ANCHOR_END: ConsensusProposalUpdate
-
-/// Parameters for `Consensus::UnstakeRequest`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusUnstakeRequestParams
-pub struct ConsensusUnstakeRequestParamsV1 {
-    /// Burnt token revealed info
-    pub input: ConsensusInput,
-    /// Anonymous output
-    pub output: Output,
-}
-// ANCHOR_END: ConsensusUnstakeRequestParams
-
-// ======================================================================
-// Consensus parameters configuration
-// NOTE: In case of changes, always verify that the `pallas::Base` consts
-// are correct using the `pallas_constants` tool in `script/research/`.
-// ======================================================================
-/// Number of slots in one epoch
-pub const EPOCH_LENGTH: u64 = 10;
-/// Slot time in seconds
-pub const SLOT_TIME: u64 = 90;
-// Stake/Unstake timelock length in epochs
-pub const GRACE_PERIOD: u64 = calculate_grace_period();
-/// Configured block reward (1 DRK == 1 * 10^8)
-pub const REWARD: u64 = 100_000_000;
-/// Reward `pallas::Base`, calculated by: pallas::Base::from(REWARD)
-pub const REWARD_PALLAS: pallas::Base = pallas::Base::from_raw([100000000, 0, 0, 0]);
-/// Serial prefix, calculated by: pallas::Base::from(2)
-pub const SERIAL_PREFIX: pallas::Base = pallas::Base::from_raw([2, 0, 0, 0]);
-/// Seed prefix, calculated by: pallas::Base::from(3)
-pub const SEED_PREFIX: pallas::Base = pallas::Base::from_raw([3, 0, 0, 0]);
-/// Secret key prefix, calculated by: pallas::Base::from(4)
-pub const SECRET_KEY_PREFIX: pallas::Base = pallas::Base::from_raw([4, 0, 0, 0]);
-/// Election seed y prefix, calculated by: pallas::Base::from(22)
-pub const MU_Y_PREFIX: pallas::Base = pallas::Base::from_raw([22, 0, 0, 0]);
-/// Election seed rho prefix, calculated by: pallas::Base::from(5)
-pub const MU_RHO_PREFIX: pallas::Base = pallas::Base::from_raw([5, 0, 0, 0]);
-/// Lottery headstart, calculated by: darkfi::consensus::LeadCoin::headstart()
-pub const HEADSTART: pallas::Base = pallas::Base::from_raw([
-    11731824086999220879,
-    11830614503713258191,
-    737869762948382064,
-    46116860184273879,
-]);
-
-/// Auxiliary function to calculate the grace (locked) period, denominated
-/// in epochs.
-#[inline]
-pub const fn calculate_grace_period() -> u64 {
-    // Grace period days target
-    const GRACE_PERIOD_DAYS: u64 = 2;
-
-    // 86400 seconds in a day
-    (86400 * GRACE_PERIOD_DAYS) / (SLOT_TIME * EPOCH_LENGTH)
-}

+ 0 - 146
src/contract/consensus/tests/genesis_stake_unstake.rs

@@ -1,146 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! Integration test of consensus genesis staking and unstaking for Alice.
-//!
-//! We first stake Alice some native tokes on genesis slot, and then she can
-//! propose and unstake them a couple of times.
-//!
-//! With this test, we want to confirm the consensus contract state
-//! transitions work for a single party and are able to be verified.
-
-use darkfi::Result;
-use log::info;
-
-use darkfi_consensus_contract::model::{calculate_grace_period, EPOCH_LENGTH};
-use darkfi_contract_test_harness::{init_logger, Holder, TestHarness, TxAction};
-
-#[test]
-fn consensus_contract_genesis_stake_unstake() -> Result<()> {
-    smol::block_on(async {
-        init_logger();
-
-        // Holders this test will use
-        const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
-
-        // Some numbers we want to assert
-        const ALICE_INITIAL: u64 = 1000;
-
-        // Slot to verify against
-        let mut current_slot = 0;
-
-        // Initialize harness
-        let mut th =
-            TestHarness::new(&["money".to_string(), "consensus".to_string()], false).await?;
-
-        // Now Alice can create a genesis stake transaction to mint
-        // some staked coins
-        info!(target: "consensus", "[Alice] =========================");
-        info!(target: "consensus", "[Alice] Building genesis stake tx");
-        info!(target: "consensus", "[Alice] =========================");
-        let (genesis_stake_tx, genesis_stake_params) =
-            th.genesis_stake(&Holder::Alice, ALICE_INITIAL)?;
-
-        // We are going to use alice genesis mint transaction to
-        // test some malicious cases.
-        info!(target: "consensus", "[Malicious] ===================================");
-        info!(target: "consensus", "[Malicious] Checking duplicate genesis stake tx");
-        info!(target: "consensus", "[Malicious] ===================================");
-        th.execute_erroneous_txs(
-            TxAction::ConsensusGenesisStake,
-            &Holder::Alice,
-            &[genesis_stake_tx.clone(), genesis_stake_tx.clone()],
-            current_slot,
-            1,
-        )
-        .await?;
-
-        info!(target: "consensus", "[Malicious] =============================================");
-        info!(target: "consensus", "[Malicious] Checking genesis stake tx not on genesis slot");
-        info!(target: "consensus", "[Malicious] =============================================");
-        th.execute_erroneous_txs(
-            TxAction::ConsensusGenesisStake,
-            &Holder::Alice,
-            &[genesis_stake_tx.clone()],
-            current_slot + 1,
-            1,
-        )
-        .await?;
-
-        for holder in &HOLDERS {
-            info!(target: "consensus", "[{holder:?}] ================================");
-            info!(target: "consensus", "[{holder:?}] Executing Alice genesis stake tx");
-            info!(target: "consensus", "[{holder:?}] ================================");
-            th.execute_genesis_stake_tx(
-                holder,
-                &genesis_stake_tx,
-                &genesis_stake_params,
-                current_slot,
-            )
-            .await?;
-        }
-
-        th.assert_trees(&HOLDERS);
-
-        // Gather new staked owncoin
-        let alice_staked_oc =
-            th.gather_consensus_staked_owncoin(&Holder::Alice, &genesis_stake_params.output, None)?;
-
-        // Verify values match
-        assert!(ALICE_INITIAL == alice_staked_oc.note.value);
-
-        // We simulate the proposal of genesis slot
-        // We progress 1 slot and simulate its proposal
-        current_slot += 1;
-        let slot = th.generate_slot(current_slot).await?;
-
-        // With alice's current coin value she can become the slot proposer,
-        // so she creates a proposal transaction to burn her staked coin,
-        // reward herself and mint the new coin.
-        let alice_rewarded_staked_oc = th
-            .execute_proposal(&HOLDERS, &Holder::Alice, current_slot, slot, &alice_staked_oc)
-            .await?;
-
-        // We progress after grace period
-        current_slot += calculate_grace_period() * EPOCH_LENGTH;
-        th.generate_slot(current_slot).await?;
-
-        // Alice can request for her owncoin to get unstaked
-        let alice_unstake_request_oc = th
-            .execute_unstake_request(
-                &HOLDERS,
-                &Holder::Alice,
-                current_slot,
-                &alice_rewarded_staked_oc,
-            )
-            .await?;
-
-        // We progress after grace period
-        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-
-        // Now Alice can unstake her owncoin
-        th.execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc)
-            .await?;
-
-        // Statistics
-        th.statistics();
-
-        // Thanks for reading
-        Ok(())
-    })
-}

+ 0 - 226
src/contract/consensus/tests/stake_unstake.rs

@@ -1,226 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! Integration test of consensus staking and unstaking for Alice.
-//!
-//! We first airdrop Alice native tokes, and then she can stake,
-//! propose and unstake them a couple of times.
-//! The following malicious cases are also tested:
-//!     1. Repeat staking coin
-//!     2. Proposal before grace period
-//!     3. Unstaking before grace period
-//!     4. Repeat requesting unstaking coin
-//!     5. Repeat unstaking coin
-//!     6. Use unstaked coin in proposal
-//!
-//! With this test, we want to confirm the consensus contract state
-//! transitions work for a single party and are able to be verified.
-
-use darkfi::Result;
-use log::info;
-
-use darkfi_consensus_contract::model::{calculate_grace_period, EPOCH_LENGTH};
-use darkfi_contract_test_harness::{init_logger, Holder, TestHarness, TxAction};
-use darkfi_sdk::pasta::pallas;
-
-#[test]
-fn consensus_contract_stake_unstake() -> Result<()> {
-    smol::block_on(async {
-        init_logger();
-
-        // Holders this test will use
-        const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
-
-        // Some numbers we want to assert
-        const ALICE_AIRDROP: u64 = 1000;
-
-        // Slot to verify against
-        let mut current_slot = 1;
-
-        // Initialize harness
-        let mut th =
-            TestHarness::new(&["money".to_string(), "consensus".to_string()], false).await?;
-
-        // Now Alice can airdrop some native tokens to herself
-        let alice_oc =
-            th.execute_airdrop(&HOLDERS, &Holder::Alice, ALICE_AIRDROP, current_slot).await?;
-
-        // Now Alice can stake her owncoin
-        let alice_staked_oc =
-            th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_oc, 181).await?;
-
-        // We progress after grace period
-        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-        let slot = th.generate_slot(current_slot).await?;
-
-        // With alice's current coin value she can become the slot proposer,
-        // so she creates a proposal transaction to burn her staked coin,
-        // reward herself and mint the new coin.
-        let alice_rewarded_staked_oc = th
-            .execute_proposal(&HOLDERS, &Holder::Alice, current_slot, slot, &alice_staked_oc)
-            .await?;
-
-        // We progress one slot
-        current_slot += 1;
-        th.generate_slot(current_slot).await?;
-
-        // Alice can request for her owncoin to get unstaked
-        let alice_unstake_request_oc = th
-            .execute_unstake_request(
-                &HOLDERS,
-                &Holder::Alice,
-                current_slot,
-                &alice_rewarded_staked_oc,
-            )
-            .await?;
-
-        // We progress after grace period
-        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-
-        // Now Alice can unstake her owncoin
-        let alice_unstaked_oc = th
-            .execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc)
-            .await?;
-
-        // Now Alice can stake her unstaked owncoin again to try some mallicious cases
-        let alice_staked_oc = th
-            .execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 148)
-            .await?;
-
-        // Alice tries to stake her coin again
-        info!(target: "consensus", "[Malicious] ===========================");
-        info!(target: "consensus", "[Malicious] Checking staking coin again");
-        info!(target: "consensus", "[Malicious] ===========================");
-        let (stake_tx, _, _) = th
-            .stake(&Holder::Alice, current_slot, &alice_unstaked_oc, pallas::Base::from(148))
-            .await?;
-        th.execute_erroneous_txs(
-            TxAction::ConsensusStake,
-            &Holder::Alice,
-            &[stake_tx],
-            current_slot,
-            1,
-        )
-        .await?;
-
-        // We progress one slot
-        current_slot += 1;
-        let slot = th.generate_slot(current_slot).await?;
-
-        // Since alice didn't wait for the grace period to pass, her proposal should fail
-        info!(target: "consensus", "[Malicious] =====================================");
-        info!(target: "consensus", "[Malicious] Checking proposal before grace period");
-        info!(target: "consensus", "[Malicious] =====================================");
-        let (proposal_tx, _, _, _) = th.proposal(&Holder::Alice, slot, &alice_staked_oc).await?;
-        th.execute_erroneous_proposal_tx(&Holder::Alice, &proposal_tx, current_slot).await?;
-
-        // or be able to unstake the coin
-        info!(target: "consensus", "[Malicious] ======================================");
-        info!(target: "consensus", "[Malicious] Checking unstaking before grace period");
-        info!(target: "consensus", "[Malicious] ======================================");
-        let (unstake_request_tx, _, _, _) =
-            th.unstake_request(&Holder::Alice, current_slot, &alice_staked_oc).await?;
-        th.execute_erroneous_txs(
-            TxAction::ConsensusUnstakeRequest,
-            &Holder::Alice,
-            &[unstake_request_tx],
-            current_slot,
-            1,
-        )
-        .await?;
-
-        // We progress after grace period
-        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-
-        // Alice can request for her owncoin to get unstaked
-        let alice_unstake_request_oc = th
-            .execute_unstake_request(&HOLDERS, &Holder::Alice, current_slot, &alice_staked_oc)
-            .await?;
-
-        info!(target: "consensus", "[Malicious] =====================================");
-        info!(target: "consensus", "[Malicious] Checking request unstaking coin again");
-        info!(target: "consensus", "[Malicious] =====================================");
-        let (unstake_request_tx, _, _, _) =
-            th.unstake_request(&Holder::Alice, current_slot, &alice_staked_oc).await?;
-        th.execute_erroneous_txs(
-            TxAction::ConsensusUnstakeRequest,
-            &Holder::Alice,
-            &[unstake_request_tx],
-            current_slot,
-            1,
-        )
-        .await?;
-
-        // We progress after grace period
-        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-
-        // Now Alice can unstake her owncoin
-        let alice_unstaked_oc = th
-            .execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc)
-            .await?;
-
-        info!(target: "consensus", "[Malicious] =============================");
-        info!(target: "consensus", "[Malicious] Checking unstaking coin again");
-        info!(target: "consensus", "[Malicious] =============================");
-        let (unstake_tx, _, _) = th.unstake(&Holder::Alice, &alice_unstake_request_oc)?;
-        th.execute_erroneous_txs(
-            TxAction::ConsensusUnstake,
-            &Holder::Alice,
-            &[unstake_tx],
-            current_slot,
-            1,
-        )
-        .await?;
-
-        // Now Alice can stake her unstaked owncoin again
-        let alice_staked_oc = th
-            .execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 86)
-            .await?;
-
-        // We progress after grace period
-        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-
-        // Alice can request for her owncoin to get unstaked
-        let alice_unstake_request_oc = th
-            .execute_unstake_request(&HOLDERS, &Holder::Alice, current_slot, &alice_staked_oc)
-            .await?;
-
-        // Now we will test if we can reuse token in proposal
-        current_slot += 1;
-        let slot = th.generate_slot(current_slot).await?;
-
-        info!(target: "consensus", "[Malicious] ========================================");
-        info!(target: "consensus", "[Malicious] Checking using unstaked coin in proposal");
-        info!(target: "consensus", "[Malicious] ========================================");
-        let (proposal_tx, _, _, _) = th.proposal(&Holder::Alice, slot, &alice_staked_oc).await?;
-        th.execute_erroneous_proposal_tx(&Holder::Alice, &proposal_tx, current_slot).await?;
-
-        // We progress after grace period
-        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-
-        // Now Alice can unstake her owncoin
-        th.execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc)
-            .await?;
-
-        // Statistics
-        th.statistics();
-
-        // Thanks for reading
-        Ok(())
-    })
-}

+ 1 - 66
src/contract/money/src/client/mod.rs

@@ -28,7 +28,7 @@
 
 
 use darkfi_sdk::{
 use darkfi_sdk::{
     bridgetree,
     bridgetree,
-    crypto::{pasta_prelude::*, Nullifier, SecretKey, TokenId, DARK_TOKEN_ID},
+    crypto::{Nullifier, SecretKey, TokenId},
     pasta::pallas,
     pasta::pallas,
 };
 };
 use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
 use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
@@ -53,12 +53,6 @@ pub mod token_mint_v1;
 /// `Money::TokenFreezeV1` API
 /// `Money::TokenFreezeV1` API
 pub mod token_freeze_v1;
 pub mod token_freeze_v1;
 
 
-/// `Money::StakeV1` API
-pub mod stake_v1;
-
-/// `Money::UnstakeV1` API
-pub mod unstake_v1;
-
 /// `Money::PoWRewardV1` API
 /// `Money::PoWRewardV1` API
 pub mod pow_reward_v1;
 pub mod pow_reward_v1;
 
 
@@ -145,65 +139,6 @@ pub struct OwnCoin {
     pub leaf_position: bridgetree::Position,
     pub leaf_position: bridgetree::Position,
 }
 }
 
 
-/// `ConsensusNote` holds the inner attributes of a `Coin`.
-#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct ConsensusNote {
-    /// Serial number of the coin, used for the nullifier
-    pub serial: pallas::Base,
-    /// Value of the coin
-    pub value: u64,
-    /// Epoch the coin was minted
-    pub epoch: u64,
-    /// Blinding factor for the value pedersen commitment
-    pub value_blind: pallas::Scalar,
-    /// Value of the reward
-    pub reward: u64,
-    /// Blinding factor for the reward value pedersen commitment
-    pub reward_blind: pallas::Scalar,
-}
-
-impl From<ConsensusNote> for MoneyNote {
-    fn from(consensus_note: ConsensusNote) -> Self {
-        MoneyNote {
-            serial: consensus_note.serial,
-            value: consensus_note.value,
-            token_id: *DARK_TOKEN_ID,
-            spend_hook: pallas::Base::ZERO,
-            user_data: pallas::Base::ZERO,
-            value_blind: consensus_note.value_blind,
-            token_blind: pallas::Base::ZERO,
-            memo: vec![],
-        }
-    }
-}
-
-/// `ConsensusOwnCoin` is a representation of `Coin` with its respective metadata.
-#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct ConsensusOwnCoin {
-    /// The coin hash
-    pub coin: Coin,
-    /// The attached `ConsensusNote`
-    pub note: ConsensusNote,
-    /// Coin's secret key
-    pub secret: SecretKey,
-    /// Coin's nullifier
-    pub nullifier: Nullifier,
-    /// Coin's leaf position in the Merkle tree of coins
-    pub leaf_position: bridgetree::Position,
-}
-
-impl From<ConsensusOwnCoin> for OwnCoin {
-    fn from(consensus_own_coin: ConsensusOwnCoin) -> Self {
-        OwnCoin {
-            coin: consensus_own_coin.coin,
-            note: consensus_own_coin.note.into(),
-            secret: consensus_own_coin.secret,
-            nullifier: consensus_own_coin.nullifier,
-            leaf_position: consensus_own_coin.leaf_position,
-        }
-    }
-}
-
 pub fn compute_remainder_blind(
 pub fn compute_remainder_blind(
     clear_inputs: &[crate::model::ClearInput],
     clear_inputs: &[crate::model::ClearInput],
     input_blinds: &[pallas::Scalar],
     input_blinds: &[pallas::Scalar],

+ 0 - 225
src/contract/money/src/client/stake_v1.rs

@@ -1,225 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! This API is crufty. Please rework it into something nice to read and nice to use.
-
-use darkfi::{
-    zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit},
-    zkas::ZkBinary,
-    Result,
-};
-use darkfi_sdk::{
-    bridgetree,
-    bridgetree::Hashable,
-    crypto::{
-        pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, MerkleNode, MerkleTree,
-        Nullifier, PublicKey, SecretKey, DARK_TOKEN_ID,
-    },
-    pasta::pallas,
-};
-use log::{debug, info};
-use rand::rngs::OsRng;
-
-use crate::{
-    client::{MoneyNote, OwnCoin},
-    model::{CoinAttributes, Input, MoneyStakeParamsV1, NullifierAttributes},
-};
-
-pub struct MoneyStakeCallDebris {
-    pub params: MoneyStakeParamsV1,
-    pub proofs: Vec<Proof>,
-    pub signature_secret: SecretKey,
-    pub value_blind: pallas::Scalar,
-}
-
-pub struct MoneyStakeBurnRevealed {
-    pub value_commit: pallas::Point,
-    pub token_commit: pallas::Base,
-    pub nullifier: Nullifier,
-    pub merkle_root: MerkleNode,
-    pub spend_hook: pallas::Base,
-    pub user_data_enc: pallas::Base,
-    pub signature_public: PublicKey,
-}
-
-impl MoneyStakeBurnRevealed {
-    pub fn to_vec(&self) -> Vec<pallas::Base> {
-        let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
-        let sigpub_coords = self.signature_public.inner().to_affine().coordinates().unwrap();
-
-        // NOTE: It's important to keep these in the same order
-        // as the `constrain_instance` calls in the zkas code.
-        vec![
-            self.nullifier.inner(),
-            *valcom_coords.x(),
-            *valcom_coords.y(),
-            self.token_commit,
-            self.merkle_root.inner(),
-            self.user_data_enc,
-            pallas::Base::ZERO, // We force spend_hook==0 here
-            *sigpub_coords.x(),
-            *sigpub_coords.y(),
-        ]
-    }
-}
-
-pub struct TransactionBuilderInputInfo {
-    pub leaf_position: bridgetree::Position,
-    pub merkle_path: Vec<MerkleNode>,
-    pub secret: SecretKey,
-    pub note: MoneyNote,
-}
-
-/// Struct holding necessary information to build a `Money::StakeV1` contract call.
-pub struct MoneyStakeCallBuilder {
-    /// `OwnCoin` we're given to use in this builder
-    pub coin: OwnCoin,
-    /// Merkle tree of coins used to create inclusion proofs
-    pub tree: MerkleTree,
-    /// `Burn_V1` zkas circuit ZkBinary
-    pub burn_zkbin: ZkBinary,
-    /// Proving key for the `Burn_V1` zk circuit
-    pub burn_pk: ProvingKey,
-}
-
-impl MoneyStakeCallBuilder {
-    pub fn build(&self) -> Result<MoneyStakeCallDebris> {
-        info!("Building Money::StakeV1 contract call");
-        assert!(self.coin.note.value != 0);
-        assert!(self.coin.note.token_id == *DARK_TOKEN_ID);
-
-        debug!("Building Money::StakeV1 anonymous input");
-        let leaf_position = self.coin.leaf_position;
-        let merkle_path = self.tree.witness(leaf_position, 0).unwrap();
-        let input = TransactionBuilderInputInfo {
-            leaf_position,
-            merkle_path,
-            secret: self.coin.secret,
-            note: self.coin.note.clone(),
-        };
-
-        // Create new random blinds and an ephemeral signature key
-        let value_blind = pallas::Scalar::random(&mut OsRng);
-        let token_blind = pallas::Base::random(&mut OsRng);
-        let signature_secret = SecretKey::random(&mut OsRng);
-        let user_data_blind = pallas::Base::random(&mut OsRng);
-
-        info!("Building Money::Stake V1 Burn ZK proof");
-        let (proof, public_inputs) = create_stake_burn_proof(
-            &self.burn_zkbin,
-            &self.burn_pk,
-            &input,
-            value_blind,
-            token_blind,
-            user_data_blind,
-            signature_secret,
-        )?;
-
-        let input = Input {
-            value_commit: public_inputs.value_commit,
-            token_commit: public_inputs.token_commit,
-            nullifier: public_inputs.nullifier,
-            merkle_root: public_inputs.merkle_root,
-            spend_hook: public_inputs.spend_hook,
-            user_data_enc: public_inputs.user_data_enc,
-            signature_public: public_inputs.signature_public,
-        };
-
-        // We now fill this with necessary stuff
-        let params = MoneyStakeParamsV1 { token_blind, input };
-        let proofs = vec![proof];
-
-        // Now we should have all the params, zk proof, signature secret and token blind.
-        // We return it all and let the caller deal with it.
-        let debris = MoneyStakeCallDebris { params, proofs, signature_secret, value_blind };
-        Ok(debris)
-    }
-}
-
-pub fn create_stake_burn_proof(
-    zkbin: &ZkBinary,
-    pk: &ProvingKey,
-    input: &TransactionBuilderInputInfo,
-    value_blind: pallas::Scalar,
-    token_blind: pallas::Base,
-    user_data_blind: pallas::Base,
-    signature_secret: SecretKey,
-) -> Result<(Proof, MoneyStakeBurnRevealed)> {
-    let public_key = PublicKey::from_secret(input.secret);
-    let signature_public = PublicKey::from_secret(signature_secret);
-
-    let coin = CoinAttributes {
-        public_key,
-        value: input.note.value,
-        token_id: input.note.token_id,
-        serial: input.note.serial,
-        spend_hook: input.note.spend_hook,
-        user_data: input.note.user_data,
-    }
-    .to_coin();
-
-    let nullifier = NullifierAttributes { secret_key: input.secret, coin }.to_nullifier();
-
-    let merkle_root = {
-        let position: u64 = input.leaf_position.into();
-        let mut current = MerkleNode::from(coin.inner());
-        for (level, sibling) in input.merkle_path.iter().enumerate() {
-            let level = level as u8;
-            current = if position & (1 << level) == 0 {
-                MerkleNode::combine(level.into(), &current, sibling)
-            } else {
-                MerkleNode::combine(level.into(), sibling, &current)
-            };
-        }
-        current
-    };
-
-    let user_data_enc = poseidon_hash([input.note.user_data, user_data_blind]);
-    let value_commit = pedersen_commitment_u64(input.note.value, value_blind);
-    let token_commit = poseidon_hash([input.note.token_id.inner(), token_blind]);
-
-    let public_inputs = MoneyStakeBurnRevealed {
-        value_commit,
-        token_commit,
-        nullifier,
-        merkle_root,
-        spend_hook: input.note.spend_hook,
-        user_data_enc,
-        signature_public,
-    };
-
-    let prover_witnesses = vec![
-        Witness::Base(Value::known(pallas::Base::from(input.note.value))),
-        Witness::Base(Value::known(input.note.token_id.inner())),
-        Witness::Scalar(Value::known(value_blind)),
-        Witness::Base(Value::known(token_blind)),
-        Witness::Base(Value::known(input.note.serial)),
-        Witness::Base(Value::known(input.note.spend_hook)),
-        Witness::Base(Value::known(input.note.user_data)),
-        Witness::Base(Value::known(user_data_blind)),
-        Witness::Base(Value::known(input.secret.inner())),
-        Witness::Uint32(Value::known(u64::from(input.leaf_position).try_into().unwrap())),
-        Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
-        Witness::Base(Value::known(signature_secret.inner())),
-    ];
-
-    let circuit = ZkCircuit::new(prover_witnesses, zkbin);
-    let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
-
-    Ok((proof, public_inputs))
-}

+ 0 - 199
src/contract/money/src/client/unstake_v1.rs

@@ -1,199 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-//! This API is crufty. Please rework it into something nice to read and nice to use.
-
-use darkfi::{
-    zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit},
-    zkas::ZkBinary,
-    Result,
-};
-use darkfi_sdk::{
-    crypto::{
-        note::AeadEncryptedNote, pasta_prelude::*, pedersen_commitment_u64, poseidon_hash,
-        MerkleNode, Nullifier, PublicKey, TokenId, DARK_TOKEN_ID,
-    },
-    pasta::pallas,
-};
-use log::{debug, info};
-use rand::rngs::OsRng;
-
-use crate::{
-    client::{ConsensusOwnCoin, MoneyNote},
-    model::{Coin, ConsensusInput, MoneyUnstakeParamsV1, Output},
-};
-
-pub struct MoneyUnstakeCallDebris {
-    pub params: MoneyUnstakeParamsV1,
-    pub proofs: Vec<Proof>,
-}
-
-pub struct MoneyMintRevealed {
-    pub coin: Coin,
-    pub value_commit: pallas::Point,
-    pub token_commit: pallas::Base,
-}
-
-impl MoneyMintRevealed {
-    pub fn to_vec(&self) -> Vec<pallas::Base> {
-        let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
-
-        // NOTE: It's important to keep these in the same order
-        // as the `constrain_instance` calls in the zkas code.
-        vec![self.coin.inner(), *valcom_coords.x(), *valcom_coords.y(), self.token_commit]
-    }
-}
-
-pub struct TransactionBuilderOutputInfo {
-    pub value: u64,
-    pub token_id: TokenId,
-    pub public_key: PublicKey,
-}
-
-/// Struct holding necessary information to build a `Money::UnstakeV1` contract call.
-pub struct MoneyUnstakeCallBuilder {
-    /// `ConsensusOwnCoin` we're given to use in this builder
-    pub owncoin: ConsensusOwnCoin,
-    /// Recipient pubkey of the minted output
-    pub recipient: PublicKey,
-    /// Blinding factor for value commitment
-    pub value_blind: pallas::Scalar,
-    /// Revealed nullifier
-    pub nullifier: Nullifier,
-    /// Revealed Merkle root
-    pub merkle_root: MerkleNode,
-    /// Signature public key used in the input
-    pub signature_public: PublicKey,
-    /// `Mint_V1` zkas circuit ZkBinary
-    pub mint_zkbin: ZkBinary,
-    /// Proving key for the `Mint_V1` zk circuit
-    pub mint_pk: ProvingKey,
-}
-
-impl MoneyUnstakeCallBuilder {
-    pub fn build(&self) -> Result<MoneyUnstakeCallDebris> {
-        info!("Building Money::UnstakeV1 contract call");
-        assert!(self.owncoin.note.value != 0);
-
-        debug!("Building Money::UnstakeV1 anonymous output");
-        let output = TransactionBuilderOutputInfo {
-            value: self.owncoin.note.value,
-            token_id: *DARK_TOKEN_ID,
-            public_key: self.recipient,
-        };
-
-        let serial = pallas::Base::random(&mut OsRng);
-        let spend_hook = pallas::Base::ZERO;
-        let user_data_enc = pallas::Base::random(&mut OsRng);
-        let token_blind = pallas::Base::ZERO;
-
-        info!("Building Money::UnstakeV1 Mint ZK proof");
-        let (proof, public_inputs) = create_unstake_mint_proof(
-            &self.mint_zkbin,
-            &self.mint_pk,
-            &output,
-            self.value_blind,
-            token_blind,
-            serial,
-            spend_hook,
-            user_data_enc,
-        )?;
-
-        // Encrypted note
-        let note = MoneyNote {
-            serial,
-            value: output.value,
-            token_id: output.token_id,
-            spend_hook,
-            user_data: user_data_enc,
-            value_blind: self.value_blind,
-            token_blind,
-            memo: vec![],
-        };
-
-        let encrypted_note = AeadEncryptedNote::encrypt(&note, &output.public_key, &mut OsRng)?;
-
-        let tx_output = Output {
-            value_commit: public_inputs.value_commit,
-            token_commit: public_inputs.token_commit,
-            coin: public_inputs.coin,
-            note: encrypted_note,
-        };
-
-        let tx_input = ConsensusInput {
-            epoch: self.owncoin.note.epoch,
-            value_commit: public_inputs.value_commit,
-            nullifier: self.nullifier,
-            merkle_root: self.merkle_root,
-            signature_public: self.signature_public,
-        };
-
-        // We now fill this with necessary stuff
-        let params = MoneyUnstakeParamsV1 { input: tx_input, output: tx_output };
-
-        // Now we should have all the params and zk proof.
-        // We return it all and let the caller deal with it.
-        let debris = MoneyUnstakeCallDebris { params, proofs: vec![proof] };
-        Ok(debris)
-    }
-}
-
-#[allow(clippy::too_many_arguments)]
-pub fn create_unstake_mint_proof(
-    zkbin: &ZkBinary,
-    pk: &ProvingKey,
-    output: &TransactionBuilderOutputInfo,
-    value_blind: pallas::Scalar,
-    token_blind: pallas::Base,
-    serial: pallas::Base,
-    spend_hook: pallas::Base,
-    user_data: pallas::Base,
-) -> Result<(Proof, MoneyMintRevealed)> {
-    let value_commit = pedersen_commitment_u64(output.value, value_blind);
-    let token_commit = poseidon_hash([output.token_id.inner(), token_blind]);
-    let (pub_x, pub_y) = output.public_key.xy();
-
-    let coin = Coin::from(poseidon_hash([
-        pub_x,
-        pub_y,
-        pallas::Base::from(output.value),
-        output.token_id.inner(),
-        serial,
-        spend_hook,
-        user_data,
-    ]));
-
-    let public_inputs = MoneyMintRevealed { coin, value_commit, token_commit };
-
-    let prover_witnesses = vec![
-        Witness::Base(Value::known(pub_x)),
-        Witness::Base(Value::known(pub_y)),
-        Witness::Base(Value::known(pallas::Base::from(output.value))),
-        Witness::Base(Value::known(output.token_id.inner())),
-        Witness::Base(Value::known(serial)),
-        Witness::Base(Value::known(spend_hook)),
-        Witness::Base(Value::known(user_data)),
-        Witness::Scalar(Value::known(value_blind)),
-        Witness::Base(Value::known(token_blind)),
-    ];
-
-    let circuit = ZkCircuit::new(prover_witnesses, zkbin);
-    let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
-
-    Ok((proof, public_inputs))
-}

+ 1 - 29
src/contract/money/src/entrypoint.rs

@@ -29,9 +29,8 @@ use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
 
 
 use crate::{
 use crate::{
     model::{
     model::{
-        MoneyFeeUpdateV1, MoneyGenesisMintUpdateV1, MoneyPoWRewardUpdateV1, MoneyStakeUpdateV1,
+        MoneyFeeUpdateV1, MoneyGenesisMintUpdateV1, MoneyPoWRewardUpdateV1,
         MoneyTokenFreezeUpdateV1, MoneyTokenMintUpdateV1, MoneyTransferUpdateV1,
         MoneyTokenFreezeUpdateV1, MoneyTokenMintUpdateV1, MoneyTransferUpdateV1,
-        MoneyUnstakeUpdateV1,
     },
     },
     MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
     MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
     MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_DB_VERSION, MONEY_CONTRACT_FAUCET_PUBKEYS,
     MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_DB_VERSION, MONEY_CONTRACT_FAUCET_PUBKEYS,
@@ -80,19 +79,6 @@ use token_freeze_v1::{
     money_token_freeze_process_update_v1,
     money_token_freeze_process_update_v1,
 };
 };
 
 
-/// `Money::Stake` functions
-mod stake_v1;
-use stake_v1::{
-    money_stake_get_metadata_v1, money_stake_process_instruction_v1, money_stake_process_update_v1,
-};
-
-/// `Money::Unstake` functions
-mod unstake_v1;
-use unstake_v1::{
-    money_unstake_get_metadata_v1, money_unstake_process_instruction_v1,
-    money_unstake_process_update_v1,
-};
-
 /// `Money::PoWReward` functions
 /// `Money::PoWReward` functions
 mod pow_reward_v1;
 mod pow_reward_v1;
 use pow_reward_v1::{
 use pow_reward_v1::{
@@ -209,8 +195,6 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
         MoneyFunction::GenesisMintV1 => money_genesis_mint_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::GenesisMintV1 => money_genesis_mint_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::TokenMintV1 => money_token_mint_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::TokenMintV1 => money_token_mint_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::TokenFreezeV1 => money_token_freeze_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::TokenFreezeV1 => money_token_freeze_get_metadata_v1(cid, call_idx, calls)?,
-        MoneyFunction::StakeV1 => money_stake_get_metadata_v1(cid, call_idx, calls)?,
-        MoneyFunction::UnstakeV1 => money_unstake_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::PoWRewardV1 => money_pow_reward_get_metadata_v1(cid, call_idx, calls)?,
         MoneyFunction::PoWRewardV1 => money_pow_reward_get_metadata_v1(cid, call_idx, calls)?,
     };
     };
 
 
@@ -245,8 +229,6 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
         MoneyFunction::TokenFreezeV1 => {
         MoneyFunction::TokenFreezeV1 => {
             money_token_freeze_process_instruction_v1(cid, call_idx, calls)?
             money_token_freeze_process_instruction_v1(cid, call_idx, calls)?
         }
         }
-        MoneyFunction::StakeV1 => money_stake_process_instruction_v1(cid, call_idx, calls)?,
-        MoneyFunction::UnstakeV1 => money_unstake_process_instruction_v1(cid, call_idx, calls)?,
         MoneyFunction::PoWRewardV1 => {
         MoneyFunction::PoWRewardV1 => {
             money_pow_reward_process_instruction_v1(cid, call_idx, calls)?
             money_pow_reward_process_instruction_v1(cid, call_idx, calls)?
         }
         }
@@ -293,16 +275,6 @@ fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
             Ok(money_token_freeze_process_update_v1(cid, update)?)
             Ok(money_token_freeze_process_update_v1(cid, update)?)
         }
         }
 
 
-        MoneyFunction::StakeV1 => {
-            let update: MoneyStakeUpdateV1 = deserialize(&update_data[1..])?;
-            Ok(money_stake_process_update_v1(cid, update)?)
-        }
-
-        MoneyFunction::UnstakeV1 => {
-            let update: MoneyUnstakeUpdateV1 = deserialize(&update_data[1..])?;
-            Ok(money_unstake_process_update_v1(cid, update)?)
-        }
-
         MoneyFunction::PoWRewardV1 => {
         MoneyFunction::PoWRewardV1 => {
             let update: MoneyPoWRewardUpdateV1 = deserialize(&update_data[1..])?;
             let update: MoneyPoWRewardUpdateV1 = deserialize(&update_data[1..])?;
             Ok(money_pow_reward_process_update_v1(cid, update)?)
             Ok(money_pow_reward_process_update_v1(cid, update)?)

+ 0 - 183
src/contract/money/src/entrypoint/stake_v1.rs

@@ -1,183 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::{
-    crypto::{pasta_prelude::*, poseidon_hash, ContractId, CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID},
-    dark_tree::DarkLeaf,
-    db::{db_contains_key, db_lookup, db_set},
-    error::{ContractError, ContractResult},
-    msg,
-    pasta::pallas,
-    ContractCall,
-};
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
-
-use crate::{
-    error::MoneyError,
-    model::{ConsensusStakeParamsV1, MoneyStakeParamsV1, MoneyStakeUpdateV1},
-    MoneyFunction, MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_NULLIFIERS_TREE,
-    MONEY_CONTRACT_ZKAS_BURN_NS_V1,
-};
-
-/// `get_metadata` function for `Money::StakeV1`
-pub(crate) fn money_stake_get_metadata_v1(
-    _cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: MoneyStakeParamsV1 = deserialize(&self_.data[1..])?;
-    let input = &params.input;
-
-    // Public inputs for the ZK proofs we have to verify
-    let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
-    // Public keys for the transaction signatures we have to verify
-    let signature_pubkeys = vec![input.signature_public];
-
-    // Grab the pedersen commitments and signature pubkeys from the
-    // anonymous input
-    let value_coords = input.value_commit.to_affine().coordinates().unwrap();
-    let (sig_x, sig_y) = input.signature_public.xy();
-
-    // It is very important that these are in the same order as the
-    // `constrain_instance` calls in the zkas code.
-    // Otherwise verification will fail.
-    zk_public_inputs.push((
-        MONEY_CONTRACT_ZKAS_BURN_NS_V1.to_string(),
-        vec![
-            input.nullifier.inner(),
-            *value_coords.x(),
-            *value_coords.y(),
-            input.token_commit,
-            input.merkle_root.inner(),
-            input.user_data_enc,
-            pallas::Base::ZERO, // We enforce spend_hook==0
-            sig_x,
-            sig_y,
-        ],
-    ));
-
-    // Serialize everything gathered and return it
-    let mut metadata = vec![];
-    zk_public_inputs.encode(&mut metadata)?;
-    signature_pubkeys.encode(&mut metadata)?;
-
-    Ok(metadata)
-}
-
-/// `process_instruction` function for `Money::StakeV1`
-pub(crate) fn money_stake_process_instruction_v1(
-    cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize];
-    let params: MoneyStakeParamsV1 = deserialize(&self_.data.data[1..])?;
-
-    // Access the necessary databases where there is information to
-    // validate this state transition.
-    let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
-    let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
-
-    // ===================================
-    // Perform the actual state transition
-    // ===================================
-
-    msg!("[MoneyStakeV1] Validating anonymous input");
-    let input = &params.input;
-
-    // Spend hook should be zero so there's no protocol holding the tokens back.
-    if input.spend_hook != pallas::Base::ZERO {
-        msg!("[MoneyStakeV1] Error: Input has a non-zero spend hook set");
-        return Err(MoneyError::SpendHookNonZero.into())
-    }
-
-    // Only native token can be staked
-    if input.token_commit != poseidon_hash([DARK_TOKEN_ID.inner(), params.token_blind]) {
-        msg!("[MoneyStakeV1] Error: Input used non-native token");
-        return Err(MoneyError::StakeInputNonNativeToken.into())
-    }
-
-    // The Merkle root is used to know whether this is a coin that
-    // existed in a previous state.
-    if !db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
-        msg!("[MoneyStakeV1] Error: Merkle root not found in previous state");
-        return Err(MoneyError::TransferMerkleRootNotFound.into())
-    }
-
-    // The nullifiers should not already exist. It is the double-spend protection.
-    if db_contains_key(nullifiers_db, &serialize(&input.nullifier))? {
-        msg!("[MoneyStakeV1] Error: Duplicate nullifier found");
-        return Err(MoneyError::DuplicateNullifier.into())
-    }
-
-    // Check parent call is consensus contract
-    let parent_call_idx = self_.parent_index;
-    if parent_call_idx.is_none() {
-        msg!("[MoneyStakeV1] Error: parent_call_idx is missing");
-        return Err(MoneyError::StakeParentCallNotConsensusContract.into())
-    }
-    let parent_call_idx = parent_call_idx.unwrap();
-
-    if parent_call_idx >= calls.len() {
-        msg!("[MoneyStakeV1] Error: next_call_idx out of bounds");
-        return Err(MoneyError::CallIdxOutOfBounds.into())
-    }
-
-    // Verify parent call corresponds to Consensus::StakeV1 (0x01)
-    let parent = &calls[parent_call_idx].data;
-    if parent.contract_id.inner() != CONSENSUS_CONTRACT_ID.inner() {
-        msg!("[MoneyStakeV1] Error: Parent contract call is not consensus contract");
-        return Err(MoneyError::StakeParentCallNotConsensusContract.into())
-    }
-
-    if parent.data[0] != 0x01 {
-        msg!("[MoneyStakeV1] Error: Parent call function mismatch");
-        return Err(MoneyError::ParentCallFunctionMismatch.into())
-    }
-
-    // Verify parent call ConsensusInput is the same as this calls input
-    let parent_params: ConsensusStakeParamsV1 = deserialize(&parent.data[1..])?;
-    if input != &parent_params.input {
-        msg!("[MoneyStakeV1] Error: Parent call input mismatch");
-        return Err(MoneyError::ParentCallInputMismatch.into())
-    }
-
-    // At this point the state transition has passed, so we create a state update
-    let update = MoneyStakeUpdateV1 { nullifier: input.nullifier };
-    let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::StakeV1 as u8)?;
-    update.encode(&mut update_data)?;
-
-    // and return it
-    Ok(update_data)
-}
-
-/// `process_update` function for `Money::StakeV1`
-pub(crate) fn money_stake_process_update_v1(
-    cid: ContractId,
-    update: MoneyStakeUpdateV1,
-) -> ContractResult {
-    // Grab all necessary db handles for where we want to write
-    let nullifiers_db = db_lookup(cid, MONEY_CONTRACT_NULLIFIERS_TREE)?;
-
-    msg!("[MoneyStakeV1] Adding new nullifier to the set");
-    db_set(nullifiers_db, &serialize(&update.nullifier), &[])?;
-
-    Ok(())
-}

+ 0 - 199
src/contract/money/src/entrypoint/unstake_v1.rs

@@ -1,199 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::{
-    crypto::{
-        pasta_prelude::*, poseidon_hash, ContractId, MerkleNode, PublicKey, CONSENSUS_CONTRACT_ID,
-        DARK_TOKEN_ID,
-    },
-    dark_tree::DarkLeaf,
-    db::{db_contains_key, db_lookup, db_set},
-    error::{ContractError, ContractResult},
-    merkle_add, msg,
-    pasta::pallas,
-    ContractCall,
-};
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
-
-use crate::{
-    error::MoneyError,
-    model::{ConsensusUnstakeParamsV1, MoneyUnstakeParamsV1, MoneyUnstakeUpdateV1},
-    MoneyFunction, CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE,
-    MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
-    MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
-};
-
-/// `get_metadata` function for `Money::UnstakeV1`
-pub(crate) fn money_unstake_get_metadata_v1(
-    _cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize].data;
-    let params: MoneyUnstakeParamsV1 = deserialize(&self_.data[1..])?;
-
-    // Public inputs for the ZK proofs we have to verify
-    let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
-    // We don't have to verify any signatures here, since they're already
-    // in the previous contract call (Consensus::UnstakeV1)
-    let signature_pubkeys: Vec<PublicKey> = vec![];
-
-    // Grab the pedersen commitment from the anonymous output
-    let value_coords = params.output.value_commit.to_affine().coordinates().unwrap();
-
-    zk_public_inputs.push((
-        MONEY_CONTRACT_ZKAS_MINT_NS_V1.to_string(),
-        vec![
-            params.output.coin.inner(),
-            *value_coords.x(),
-            *value_coords.y(),
-            params.output.token_commit,
-        ],
-    ));
-
-    // Serialize everything gathered and return it
-    let mut metadata = vec![];
-    zk_public_inputs.encode(&mut metadata)?;
-    signature_pubkeys.encode(&mut metadata)?;
-    Ok(metadata)
-}
-
-/// `process_instruction` function for `Money::UnstakeV1`
-pub(crate) fn money_unstake_process_instruction_v1(
-    cid: ContractId,
-    call_idx: u32,
-    calls: Vec<DarkLeaf<ContractCall>>,
-) -> Result<Vec<u8>, ContractError> {
-    let self_ = &calls[call_idx as usize];
-    let params: MoneyUnstakeParamsV1 = deserialize(&self_.data.data[1..])?;
-    let input = &params.input;
-    let output = &params.output;
-
-    // Access the necessary databases where there is information to
-    // validate this state transition.
-    let money_coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
-    let consensus_nullifiers_db =
-        db_lookup(*CONSENSUS_CONTRACT_ID, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
-    let consensus_unstaked_coin_roots_db =
-        db_lookup(*CONSENSUS_CONTRACT_ID, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?;
-
-    // ===================================
-    // Perform the actual state transition
-    // ===================================
-
-    // Check child call is consensus contract
-    if call_idx == 0 {
-        msg!("[MoneyUnstakeV1] Error: child_call_idx will be out of bounds");
-        return Err(MoneyError::CallIdxOutOfBounds.into())
-    }
-
-    let child_call_indexes = &self_.children_indexes;
-    if child_call_indexes.len() != 1 {
-        msg!("[MoneyUnstakeV1] Error: child_call_idx is missing");
-        return Err(MoneyError::UnstakeChildCallNotConsensusContract.into())
-    }
-    let child_call_idx = child_call_indexes[0];
-
-    let child = &calls[child_call_idx].data;
-    if child.contract_id.inner() != CONSENSUS_CONTRACT_ID.inner() {
-        msg!("[MoneyUnstakeV1] Error: Child contract call is not consensus contract");
-        return Err(MoneyError::UnstakeChildCallNotConsensusContract.into())
-    }
-
-    // Verify child call corresponds to Consensus::UnstakeV1 (0x04)
-    if child.data[0] != 0x04 {
-        msg!("[MoneyUnstakeV1] Error: Child call function mismatch");
-        return Err(MoneyError::ChildCallFunctionMismatch.into())
-    }
-
-    // Verify child call input is the same as this calls StakeInput
-    let child_params: ConsensusUnstakeParamsV1 = deserialize(&child.data[1..])?;
-    let child_input = &child_params.input;
-    if child_input != input {
-        msg!("[MoneyUnstakeV1] Error: Child call input mismatch");
-        return Err(MoneyError::ChildCallInputMismatch.into())
-    }
-
-    msg!("[MoneyUnstakeV1] Validating anonymous output");
-    // Only native token can be minted here.
-    // Since consensus coins don't have token commitments, we use zero as
-    // the token blind for the token commitment of the newly minted token
-    if output.token_commit != poseidon_hash([DARK_TOKEN_ID.inner(), pallas::Base::ZERO]) {
-        msg!("[MoneyUnstakeV1] Error: Input used non-native token");
-        return Err(MoneyError::StakeInputNonNativeToken.into())
-    }
-
-    // Verify value commits match
-    if output.value_commit != input.value_commit {
-        msg!("[MoneyUnstakeV1] Error: Value commitments do not match");
-        return Err(MoneyError::ValueMismatch.into())
-    }
-
-    // The Merkle root is used to know whether this is a coin that
-    // existed in a previous state.
-    if !db_contains_key(consensus_unstaked_coin_roots_db, &serialize(&input.merkle_root))? {
-        msg!("[MoneyUnstakeV1] Error: Merkle root not found in previous state");
-        return Err(MoneyError::TransferMerkleRootNotFound.into())
-    }
-
-    // The nullifiers should already exist in the Consensus nullifier set
-    if !db_contains_key(consensus_nullifiers_db, &serialize(&input.nullifier))? {
-        msg!("[MoneyUnstakeV1] Error: Nullifier not found in Consensus nullifier set");
-        return Err(MoneyError::MissingNullifier.into())
-    }
-
-    // Newly created coin for this call is in the output. Here we gather it,
-    // and we also check that it hasn't existed before.
-    if db_contains_key(money_coins_db, &serialize(&output.coin))? {
-        msg!("[MoneyUnstakeV1] Error: Duplicate coin found in output");
-        return Err(MoneyError::DuplicateCoin.into())
-    }
-
-    // Create a state update.
-    let update = MoneyUnstakeUpdateV1 { coin: output.coin };
-    let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::UnstakeV1 as u8)?;
-    update.encode(&mut update_data)?;
-    Ok(update_data)
-}
-
-/// `process_update` function for `Money::UnstakeV1`
-pub(crate) fn money_unstake_process_update_v1(
-    cid: ContractId,
-    update: MoneyUnstakeUpdateV1,
-) -> ContractResult {
-    // Grab all necessary db handles for where we want to write
-    let info_db = db_lookup(cid, MONEY_CONTRACT_INFO_TREE)?;
-    let coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
-    let coin_roots_db = db_lookup(cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
-
-    msg!("[MoneyUnstakeV1] Adding new coin to the set");
-    db_set(coins_db, &serialize(&update.coin), &[])?;
-
-    msg!("[MoneyUnstakeV1] Adding new coin to the Merkle tree");
-    let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
-    merkle_add(
-        info_db,
-        coin_roots_db,
-        MONEY_CONTRACT_LATEST_COIN_ROOT,
-        MONEY_CONTRACT_COIN_MERKLE_TREE,
-        &coins,
-    )?;
-
-    Ok(())
-}

+ 14 - 46
src/contract/money/src/error.rs

@@ -76,30 +76,6 @@ pub enum MoneyError {
     #[error("Token mint is frozen")]
     #[error("Token mint is frozen")]
     TokenMintFrozen,
     TokenMintFrozen,
 
 
-    #[error("Input used non-native token")]
-    StakeInputNonNativeToken,
-
-    #[error("Missing spend hook")]
-    StakeMissingSpendHook,
-
-    #[error("Missing nullifier")]
-    StakeMissingNullifier,
-
-    #[error("Parent contract call is not consensus contract")]
-    StakeParentCallNotConsensusContract,
-
-    #[error("Child contract call is not money contract")]
-    StakeChildCallNotMoneyContract,
-
-    #[error("Spend hook is not consensus contract")]
-    UnstakeSpendHookNotConsensusContract,
-
-    #[error("Parent contract call is not money contract")]
-    UnstakeParentCallNotMoneyContract,
-
-    #[error("Child contract call is not consensus contract")]
-    UnstakeChildCallNotConsensusContract,
-
     #[error("Parent call function mismatch")]
     #[error("Parent call function mismatch")]
     ParentCallFunctionMismatch,
     ParentCallFunctionMismatch,
 
 
@@ -165,28 +141,20 @@ impl From<MoneyError> for ContractError {
             MoneyError::SwapMerkleRootNotFound => Self::Custom(16),
             MoneyError::SwapMerkleRootNotFound => Self::Custom(16),
             MoneyError::TokenIdDoesNotDeriveFromMint => Self::Custom(17),
             MoneyError::TokenIdDoesNotDeriveFromMint => Self::Custom(17),
             MoneyError::TokenMintFrozen => Self::Custom(18),
             MoneyError::TokenMintFrozen => Self::Custom(18),
-            MoneyError::StakeInputNonNativeToken => Self::Custom(19),
-            MoneyError::StakeMissingSpendHook => Self::Custom(20),
-            MoneyError::StakeMissingNullifier => Self::Custom(21),
-            MoneyError::StakeParentCallNotConsensusContract => Self::Custom(22),
-            MoneyError::StakeChildCallNotMoneyContract => Self::Custom(23),
-            MoneyError::UnstakeSpendHookNotConsensusContract => Self::Custom(24),
-            MoneyError::UnstakeParentCallNotMoneyContract => Self::Custom(25),
-            MoneyError::UnstakeChildCallNotConsensusContract => Self::Custom(26),
-            MoneyError::ParentCallFunctionMismatch => Self::Custom(27),
-            MoneyError::ParentCallInputMismatch => Self::Custom(28),
-            MoneyError::ChildCallFunctionMismatch => Self::Custom(29),
-            MoneyError::ChildCallInputMismatch => Self::Custom(30),
-            MoneyError::GenesisCallNonGenesisBlock => Self::Custom(31),
-            MoneyError::GenesisCallNonGenesisSlot => Self::Custom(32),
-            MoneyError::MissingNullifier => Self::Custom(33),
-            MoneyError::PoWRewardCallAfterCutoffBlockHeight => Self::Custom(34),
-            MoneyError::PoWRewardMissingSlot => Self::Custom(35),
-            MoneyError::PoWRewardExtendsUnknownFork => Self::Custom(36),
-            MoneyError::PoWRewardErroneousVrfProof => Self::Custom(37),
-            MoneyError::FeeMissingInputs => Self::Custom(38),
-            MoneyError::InsufficientFee => Self::Custom(39),
-            MoneyError::CoinMerkleRootNotFound => Self::Custom(40),
+            MoneyError::ParentCallFunctionMismatch => Self::Custom(19),
+            MoneyError::ParentCallInputMismatch => Self::Custom(20),
+            MoneyError::ChildCallFunctionMismatch => Self::Custom(21),
+            MoneyError::ChildCallInputMismatch => Self::Custom(22),
+            MoneyError::GenesisCallNonGenesisBlock => Self::Custom(23),
+            MoneyError::GenesisCallNonGenesisSlot => Self::Custom(24),
+            MoneyError::MissingNullifier => Self::Custom(25),
+            MoneyError::PoWRewardCallAfterCutoffBlockHeight => Self::Custom(26),
+            MoneyError::PoWRewardMissingSlot => Self::Custom(27),
+            MoneyError::PoWRewardExtendsUnknownFork => Self::Custom(28),
+            MoneyError::PoWRewardErroneousVrfProof => Self::Custom(29),
+            MoneyError::FeeMissingInputs => Self::Custom(30),
+            MoneyError::InsufficientFee => Self::Custom(31),
+            MoneyError::CoinMerkleRootNotFound => Self::Custom(32),
         }
         }
     }
     }
 }
 }

+ 2 - 32
src/contract/money/src/lib.rs

@@ -31,9 +31,7 @@ pub enum MoneyFunction {
     OtcSwapV1 = 0x03,
     OtcSwapV1 = 0x03,
     TokenMintV1 = 0x04,
     TokenMintV1 = 0x04,
     TokenFreezeV1 = 0x05,
     TokenFreezeV1 = 0x05,
-    StakeV1 = 0x06,
-    UnstakeV1 = 0x07,
-    PoWRewardV1 = 0x08,
+    PoWRewardV1 = 0x06,
 }
 }
 // ANCHOR_END: money-function
 // ANCHOR_END: money-function
 
 
@@ -48,9 +46,7 @@ impl TryFrom<u8> for MoneyFunction {
             0x03 => Ok(Self::OtcSwapV1),
             0x03 => Ok(Self::OtcSwapV1),
             0x04 => Ok(Self::TokenMintV1),
             0x04 => Ok(Self::TokenMintV1),
             0x05 => Ok(Self::TokenFreezeV1),
             0x05 => Ok(Self::TokenFreezeV1),
-            0x06 => Ok(Self::StakeV1),
-            0x07 => Ok(Self::UnstakeV1),
-            0x08 => Ok(Self::PoWRewardV1),
+            0x06 => Ok(Self::PoWRewardV1),
             _ => Err(ContractError::InvalidFunction),
             _ => Err(ContractError::InvalidFunction),
         }
         }
     }
     }
@@ -94,29 +90,3 @@ pub const MONEY_CONTRACT_ZKAS_BURN_NS_V1: &str = "Burn_V1";
 pub const MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1: &str = "TokenMint_V1";
 pub const MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1: &str = "TokenMint_V1";
 /// zkas token freeze circuit namespace
 /// zkas token freeze circuit namespace
 pub const MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1: &str = "TokenFreeze_V1";
 pub const MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1: &str = "TokenFreeze_V1";
-
-// These are the different sled trees that will be created
-// for the consensus contract.
-// We keep them here so we can reference them both in `Money`
-// and `Consensus` contracts.
-pub const CONSENSUS_CONTRACT_INFO_TREE: &str = "consensus_info";
-pub const CONSENSUS_CONTRACT_NULLIFIERS_TREE: &str = "consensus_nullifiers";
-pub const CONSENSUS_CONTRACT_STAKED_COINS_TREE: &str = "consensus_staked_coins";
-pub const CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE: &str = "consensus_unstaked_coins";
-pub const CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE: &str = "consensus_staked_coin_roots";
-pub const CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE: &str = "consensus_unstaked_coin_roots";
-
-// These are keys inside the consensus info tree
-pub const CONSENSUS_CONTRACT_DB_VERSION: &[u8] = b"db_version";
-pub const CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE: &[u8] = b"consensus_staked_coin_tree";
-pub const CONSENSUS_CONTRACT_STAKED_COIN_LATEST_COIN_ROOT: &[u8] = b"consensus_staked_last_root";
-pub const CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE: &[u8] = b"consensus_unstaked_coin_tree";
-pub const CONSENSUS_CONTRACT_UNSTAKED_COIN_LATEST_COIN_ROOT: &[u8] =
-    b"consensus_unstaked_last_root";
-
-/// zkas consensus mint circuit namespace
-pub const CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1: &str = "ConsensusMint_V1";
-/// zkas consensus burn circuit namespace
-pub const CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1: &str = "ConsensusBurn_V1";
-/// zkas proposal circuit namespace
-pub const CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1: &str = "ConsensusProposal_V1";

+ 0 - 113
src/contract/money/src/model.rs

@@ -163,32 +163,6 @@ pub struct Output {
 }
 }
 // ANCHOR_END: money-output
 // ANCHOR_END: money-output
 
 
-/// Anonymous input for consensus contract calls
-#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct ConsensusInput {
-    /// Epoch the coin was minted
-    pub epoch: u64,
-    /// Pedersen commitment for the staked coin's value
-    pub value_commit: pallas::Point,
-    /// Revealed nullifier
-    pub nullifier: Nullifier,
-    /// Revealed Merkle root
-    pub merkle_root: MerkleNode,
-    /// Public key for the signature
-    pub signature_public: PublicKey,
-}
-
-/// A consensus contract call's anonymous output
-#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct ConsensusOutput {
-    /// Pedersen commitment for the output's value
-    pub value_commit: pallas::Point,
-    /// Minted coin
-    pub coin: Coin,
-    /// AEAD encrypted note
-    pub note: AeadEncryptedNote,
-}
-
 /// Parameters for `Money::Fee`
 /// Parameters for `Money::Fee`
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 pub struct MoneyFeeParamsV1 {
 pub struct MoneyFeeParamsV1 {
@@ -304,90 +278,3 @@ pub struct MoneyPoWRewardUpdateV1 {
     /// The newly minted coin
     /// The newly minted coin
     pub coin: Coin,
     pub coin: Coin,
 }
 }
-
-/// Parameters for `Money::Stake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: MoneyStakeParams
-pub struct MoneyStakeParamsV1 {
-    /// Blinding factor for `token_id`
-    pub token_blind: pallas::Base,
-    /// Anonymous input
-    pub input: Input,
-}
-// ANCHOR_END: MoneyStakeParams
-
-/// State update for `Money::Stake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: MoneyStakeUpdate
-pub struct MoneyStakeUpdateV1 {
-    /// Revealed nullifier
-    pub nullifier: Nullifier,
-}
-// ANCHOR_END: MoneyStakeUpdate
-
-/// Parameters for `Money::Unstake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: MoneyUnstakeParams
-pub struct MoneyUnstakeParamsV1 {
-    /// Burnt token revealed info
-    pub input: ConsensusInput,
-    /// Anonymous output
-    pub output: Output,
-}
-// ANCHOR_END: MoneyUnstakeParams
-
-/// State update for `Money::Unstake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: MoneyUnstakeUpdate
-pub struct MoneyUnstakeUpdateV1 {
-    /// The newly minted coin
-    pub coin: Coin,
-}
-// ANCHOR_END: MoneyUnstakeUpdate
-
-/// Parameters for `Consensus::Stake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusStakeParams
-pub struct ConsensusStakeParamsV1 {
-    /// Burnt token revealed info
-    pub input: Input,
-    /// Anonymous output
-    pub output: ConsensusOutput,
-}
-// ANCHOR_END: ConsensusStakeParams
-
-/// State update for `Consensus::Stake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusStakeUpdate
-pub struct ConsensusStakeUpdateV1 {
-    /// The newly minted coin
-    pub coin: Coin,
-}
-// ANCHOR_END: ConsensusStakeUpdate
-
-/// Parameters for `Consensus::UnstakeRequest`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusUnstakeReqParams
-pub struct ConsensusUnstakeReqParamsV1 {
-    pub input: ConsensusInput,
-    pub output: ConsensusOutput,
-}
-// ANCHOR_END: ConsensusUnstakeReqParams
-
-/// Parameters for `Consensus::Unstake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusUnstakeParams
-pub struct ConsensusUnstakeParamsV1 {
-    /// Anonymous input
-    pub input: ConsensusInput,
-}
-// ANCHOR_END: ConsensusUnstakeParams
-
-/// State update for `Consensus::Unstake`
-#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
-// ANCHOR: ConsensusUnstakeUpdate
-pub struct ConsensusUnstakeUpdateV1 {
-    /// Revealed nullifier
-    pub nullifier: Nullifier,
-}
-// ANCHOR_END: ConsensusUnstakeUpdate

+ 0 - 1
src/contract/test-harness/Cargo.toml

@@ -11,7 +11,6 @@ darkfi-sdk = {path = "../../../src/sdk"}
 darkfi-serial = {path = "../../../src/serial", features = ["crypto"]}
 darkfi-serial = {path = "../../../src/serial", features = ["crypto"]}
 darkfi_dao_contract = {path = "../dao", features = ["client", "no-entrypoint"]}
 darkfi_dao_contract = {path = "../dao", features = ["client", "no-entrypoint"]}
 darkfi_money_contract = {path = "../money", features = ["client", "no-entrypoint"]}
 darkfi_money_contract = {path = "../money", features = ["client", "no-entrypoint"]}
-darkfi_consensus_contract = {path = "../consensus", features = ["client", "no-entrypoint"]}
 darkfi_deployooor_contract = {path = "../deployooor", features = ["client", "no-entrypoint"]}
 darkfi_deployooor_contract = {path = "../deployooor", features = ["client", "no-entrypoint"]}
 
 
 num-bigint = "0.4.4"
 num-bigint = "0.4.4"

+ 0 - 119
src/contract/test-harness/src/consensus_genesis_stake.rs

@@ -1,119 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::time::Instant;
-
-use darkfi::{
-    tx::{ContractCallLeaf, Transaction, TransactionBuilder},
-    zk::halo2::Field,
-    Result,
-};
-use darkfi_consensus_contract::{
-    client::genesis_stake_v1::ConsensusGenesisStakeCallBuilder,
-    model::ConsensusGenesisStakeParamsV1, ConsensusFunction,
-};
-use darkfi_money_contract::CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1;
-use darkfi_sdk::{
-    crypto::{MerkleNode, CONSENSUS_CONTRACT_ID},
-    pasta::pallas,
-    ContractCall,
-};
-use darkfi_serial::{serialize, Encodable};
-use rand::rngs::OsRng;
-
-use super::{Holder, TestHarness, TxAction};
-
-impl TestHarness {
-    pub fn genesis_stake(
-        &mut self,
-        holder: &Holder,
-        amount: u64,
-    ) -> Result<(Transaction, ConsensusGenesisStakeParamsV1)> {
-        let wallet = self.holders.get(holder).unwrap();
-
-        let (mint_pk, mint_zkbin) =
-            self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1.to_string()).unwrap();
-
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusGenesisStake).unwrap();
-
-        let timer = Instant::now();
-
-        // Building Consensus::GenesisStake params
-        let genesis_stake_call_debris = ConsensusGenesisStakeCallBuilder {
-            keypair: wallet.keypair,
-            recipient: wallet.keypair.public,
-            amount,
-            mint_zkbin: mint_zkbin.clone(),
-            mint_pk: mint_pk.clone(),
-        }
-        .build_with_params(
-            pallas::Scalar::random(&mut OsRng),
-            pallas::Base::random(&mut OsRng),
-            pallas::Scalar::random(&mut OsRng),
-            pallas::Base::from(62),
-        )?;
-
-        let (genesis_stake_params, genesis_stake_proofs) =
-            (genesis_stake_call_debris.params, genesis_stake_call_debris.proofs);
-
-        // Building genesis stake tx
-        let mut data = vec![ConsensusFunction::GenesisStakeV1 as u8];
-        genesis_stake_params.encode(&mut data)?;
-        let contract_call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
-        let mut genesis_stake_tx_builder = TransactionBuilder::new(
-            ContractCallLeaf { call: contract_call, proofs: genesis_stake_proofs },
-            vec![],
-        )?;
-        let mut genesis_stake_tx = genesis_stake_tx_builder.build()?;
-        let sigs = genesis_stake_tx.create_sigs(&mut OsRng, &[wallet.keypair.secret])?;
-        genesis_stake_tx.signatures = vec![sigs];
-        tx_action_benchmark.creation_times.push(timer.elapsed());
-
-        // Calculate transaction sizes
-        let encoded: Vec<u8> = serialize(&genesis_stake_tx);
-        let size = std::mem::size_of_val(&*encoded);
-        tx_action_benchmark.sizes.push(size);
-        let base58 = bs58::encode(&encoded).into_string();
-        let size = std::mem::size_of_val(&*base58);
-        tx_action_benchmark.broadcasted_sizes.push(size);
-
-        Ok((genesis_stake_tx, genesis_stake_params))
-    }
-
-    pub async fn execute_genesis_stake_tx(
-        &mut self,
-        holder: &Holder,
-        tx: &Transaction,
-        params: &ConsensusGenesisStakeParamsV1,
-        slot: u64,
-    ) -> Result<()> {
-        let wallet = self.holders.get_mut(holder).unwrap();
-
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusGenesisStake).unwrap();
-
-        let timer = Instant::now();
-
-        wallet.validator.add_transactions(&[tx.clone()], slot, true).await?;
-        wallet.consensus_staked_merkle_tree.append(MerkleNode::from(params.output.coin.inner()));
-        tx_action_benchmark.verify_times.push(timer.elapsed());
-
-        Ok(())
-    }
-}

+ 0 - 179
src/contract/test-harness/src/consensus_proposal.rs

@@ -1,179 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::time::Instant;
-
-use darkfi::{
-    tx::{ContractCallLeaf, Transaction, TransactionBuilder},
-    Result,
-};
-use darkfi_consensus_contract::{
-    client::proposal_v1::ConsensusProposalCallBuilder,
-    model::{ConsensusProposalParamsV1, REWARD},
-    ConsensusFunction,
-};
-use darkfi_money_contract::{client::ConsensusOwnCoin, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1};
-use darkfi_sdk::{
-    blockchain::Slot,
-    crypto::{MerkleNode, SecretKey, CONSENSUS_CONTRACT_ID},
-    ContractCall,
-};
-use darkfi_serial::{serialize, Encodable};
-use log::info;
-use rand::rngs::OsRng;
-
-use super::{Holder, TestHarness, TxAction};
-
-impl TestHarness {
-    pub async fn proposal(
-        &mut self,
-        holder: &Holder,
-        slot: Slot,
-        staked_oc: &ConsensusOwnCoin,
-    ) -> Result<(Transaction, ConsensusProposalParamsV1, SecretKey, SecretKey)> {
-        let wallet = self.holders.get(holder).unwrap();
-
-        let (proposal_pk, proposal_zkbin) =
-            self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1.to_string()).unwrap();
-
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusProposal).unwrap();
-
-        let timer = Instant::now();
-
-        // Proposals always extend genesis block
-        let fork_hash = self.genesis_block.hash()?;
-
-        // Building Consensus::Propose params
-        let proposal_call_debris = ConsensusProposalCallBuilder {
-            owncoin: staked_oc.clone(),
-            slot,
-            fork_hash,
-            fork_previous_hash: fork_hash,
-            merkle_tree: wallet.consensus_staked_merkle_tree.clone(),
-            proposal_zkbin: proposal_zkbin.clone(),
-            proposal_pk: proposal_pk.clone(),
-        }
-        .build()?;
-
-        let (params, proofs, output_keypair, signature_secret_key) = (
-            proposal_call_debris.params,
-            proposal_call_debris.proofs,
-            proposal_call_debris.keypair,
-            proposal_call_debris.signature_secret,
-        );
-
-        let mut data = vec![ConsensusFunction::ProposalV1 as u8];
-        params.encode(&mut data)?;
-        let call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
-        let mut tx_builder = TransactionBuilder::new(ContractCallLeaf { call, proofs }, vec![])?;
-        let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&mut OsRng, &[signature_secret_key])?;
-        tx.signatures = vec![sigs];
-        tx_action_benchmark.creation_times.push(timer.elapsed());
-
-        // Calculate transaction sizes
-        let encoded: Vec<u8> = serialize(&tx);
-        let size = std::mem::size_of_val(&*encoded);
-        tx_action_benchmark.sizes.push(size);
-        let base58 = bs58::encode(&encoded).into_string();
-        let size = std::mem::size_of_val(&*base58);
-        tx_action_benchmark.broadcasted_sizes.push(size);
-
-        Ok((tx, params, signature_secret_key, output_keypair.secret))
-    }
-
-    pub async fn execute_proposal_tx(
-        &mut self,
-        holder: &Holder,
-        tx: &Transaction,
-        params: &ConsensusProposalParamsV1,
-        slot: u64,
-    ) -> Result<()> {
-        let wallet = self.holders.get_mut(holder).unwrap();
-
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusProposal).unwrap();
-
-        let timer = Instant::now();
-
-        wallet.validator.add_test_producer_transaction(tx, slot, 2, true).await?;
-        wallet.consensus_staked_merkle_tree.append(MerkleNode::from(params.output.coin.inner()));
-        tx_action_benchmark.verify_times.push(timer.elapsed());
-
-        Ok(())
-    }
-
-    // Execute a proposal transaction and gather rewarded coin
-    pub async fn execute_proposal(
-        &mut self,
-        holders: &[Holder],
-        holder: &Holder,
-        current_slot: u64,
-        slot: Slot,
-        staked_oc: &ConsensusOwnCoin,
-    ) -> Result<ConsensusOwnCoin> {
-        info!(target: "consensus", "[{holder:?}] ====================");
-        info!(target: "consensus", "[{holder:?}] Building proposal tx");
-        info!(target: "consensus", "[{holder:?}] ====================");
-        let (
-            proposal_tx,
-            proposal_params,
-            _proposal_signing_secret_key,
-            proposal_decryption_secret_key,
-        ) = self.proposal(holder, slot, staked_oc).await?;
-
-        for h in holders {
-            info!(target: "consensus", "[{h:?}] ================================");
-            info!(target: "consensus", "[{h:?}] Executing {holder:?} proposal tx");
-            info!(target: "consensus", "[{h:?}] ================================");
-            self.execute_proposal_tx(h, &proposal_tx, &proposal_params, current_slot).await?;
-        }
-
-        self.assert_trees(holders);
-
-        // Gather new staked owncoin which includes the reward
-        let rewarded_staked_oc = self.gather_consensus_staked_owncoin(
-            holder,
-            &proposal_params.output,
-            Some(proposal_decryption_secret_key),
-        )?;
-
-        // Verify values match
-        assert!((staked_oc.note.value + REWARD) == rewarded_staked_oc.note.value);
-
-        Ok(rewarded_staked_oc)
-    }
-
-    pub async fn execute_erroneous_proposal_tx(
-        &mut self,
-        holder: &Holder,
-        tx: &Transaction,
-        slot: u64,
-    ) -> Result<()> {
-        let wallet = self.holders.get_mut(holder).unwrap();
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusProposal).unwrap();
-        let timer = Instant::now();
-
-        assert!(wallet.validator.add_test_producer_transaction(tx, slot, 2, true).await.is_err());
-        tx_action_benchmark.verify_times.push(timer.elapsed());
-
-        Ok(())
-    }
-}

+ 0 - 195
src/contract/test-harness/src/consensus_stake.rs

@@ -1,195 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::time::Instant;
-
-use darkfi::{
-    tx::{ContractCallLeaf, Transaction, TransactionBuilder},
-    Result,
-};
-use darkfi_consensus_contract::{client::stake_v1::ConsensusStakeCallBuilder, ConsensusFunction};
-use darkfi_money_contract::{
-    client::{stake_v1::MoneyStakeCallBuilder, ConsensusOwnCoin, OwnCoin},
-    model::ConsensusStakeParamsV1,
-    MoneyFunction, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
-};
-use darkfi_sdk::{
-    crypto::{MerkleNode, SecretKey, CONSENSUS_CONTRACT_ID, MONEY_CONTRACT_ID},
-    dark_tree::DarkTree,
-    pasta::pallas,
-    ContractCall,
-};
-use darkfi_serial::{serialize, Encodable};
-use log::info;
-use rand::rngs::OsRng;
-
-use super::{Holder, TestHarness, TxAction};
-
-impl TestHarness {
-    pub async fn stake(
-        &mut self,
-        holder: &Holder,
-        slot: u64,
-        owncoin: &OwnCoin,
-        serial: pallas::Base,
-    ) -> Result<(Transaction, ConsensusStakeParamsV1, SecretKey)> {
-        let wallet = self.holders.get(holder).unwrap();
-
-        let (mint_pk, mint_zkbin) =
-            self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1.to_string()).unwrap();
-
-        let (burn_pk, burn_zkbin) =
-            self.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1.to_string()).unwrap();
-
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusStake).unwrap();
-
-        let epoch = wallet.validator.consensus.time_keeper.slot_epoch(slot);
-        let timer = Instant::now();
-
-        // Building Money::Stake params
-        let money_stake_call_debris = MoneyStakeCallBuilder {
-            coin: owncoin.clone(),
-            tree: wallet.money_merkle_tree.clone(),
-            burn_zkbin: burn_zkbin.clone(),
-            burn_pk: burn_pk.clone(),
-        }
-        .build()?;
-
-        let (
-            money_stake_params,
-            money_stake_proofs,
-            money_stake_secret_key,
-            money_stake_value_blind,
-        ) = (
-            money_stake_call_debris.params,
-            money_stake_call_debris.proofs,
-            money_stake_call_debris.signature_secret,
-            money_stake_call_debris.value_blind,
-        );
-
-        // Building Consensus::Stake params
-        let consensus_stake_call_debris = ConsensusStakeCallBuilder {
-            coin: owncoin.clone(),
-            epoch,
-            value_blind: money_stake_value_blind,
-            money_input: money_stake_params.input.clone(),
-            mint_zkbin: mint_zkbin.clone(),
-            mint_pk: mint_pk.clone(),
-        }
-        .build_with_params(serial)?;
-
-        let (consensus_stake_params, consensus_stake_proofs, consensus_stake_secret_key) = (
-            consensus_stake_call_debris.params,
-            consensus_stake_call_debris.proofs,
-            consensus_stake_call_debris.signature_secret,
-        );
-
-        // Building stake tx
-        let mut data = vec![MoneyFunction::StakeV1 as u8];
-        money_stake_params.encode(&mut data)?;
-        let money_call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
-
-        let mut data = vec![ConsensusFunction::StakeV1 as u8];
-        consensus_stake_params.encode(&mut data)?;
-        let consensus_call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
-
-        let mut stake_tx_builder = TransactionBuilder::new(
-            ContractCallLeaf { call: consensus_call, proofs: consensus_stake_proofs },
-            vec![DarkTree::new(
-                ContractCallLeaf { call: money_call, proofs: money_stake_proofs },
-                vec![],
-                None,
-                None,
-            )],
-        )?;
-        let mut stake_tx = stake_tx_builder.build()?;
-        let money_sigs = stake_tx.create_sigs(&mut OsRng, &[money_stake_secret_key])?;
-        let consensus_sigs = stake_tx.create_sigs(&mut OsRng, &[consensus_stake_secret_key])?;
-        stake_tx.signatures = vec![money_sigs, consensus_sigs];
-        tx_action_benchmark.creation_times.push(timer.elapsed());
-
-        // Calculate transaction sizes
-        let encoded: Vec<u8> = serialize(&stake_tx);
-        let size = std::mem::size_of_val(&*encoded);
-        tx_action_benchmark.sizes.push(size);
-        let base58 = bs58::encode(&encoded).into_string();
-        let size = std::mem::size_of_val(&*base58);
-        tx_action_benchmark.broadcasted_sizes.push(size);
-
-        Ok((stake_tx, consensus_stake_params, consensus_stake_secret_key))
-    }
-
-    pub async fn execute_stake_tx(
-        &mut self,
-        holder: &Holder,
-        tx: &Transaction,
-        params: &ConsensusStakeParamsV1,
-        slot: u64,
-    ) -> Result<()> {
-        let wallet = self.holders.get_mut(holder).unwrap();
-
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusStake).unwrap();
-
-        let timer = Instant::now();
-
-        wallet.validator.add_transactions(&[tx.clone()], slot, true).await?;
-        wallet.consensus_staked_merkle_tree.append(MerkleNode::from(params.output.coin.inner()));
-        tx_action_benchmark.verify_times.push(timer.elapsed());
-
-        Ok(())
-    }
-
-    // Execute a stake transaction and gather the coin
-    pub async fn execute_stake(
-        &mut self,
-        holders: &[Holder],
-        holder: &Holder,
-        current_slot: u64,
-        oc: &OwnCoin,
-        serial: u64,
-    ) -> Result<ConsensusOwnCoin> {
-        info!(target: "consensus", "[{holder:?}] =================");
-        info!(target: "consensus", "[{holder:?}] Building stake tx");
-        info!(target: "consensus", "[{holder:?}] =================");
-        let (stake_tx, stake_params, stake_secret_key) =
-            self.stake(holder, current_slot, oc, pallas::Base::from(serial)).await?;
-
-        for h in holders {
-            info!(target: "consensus", "[{h:?}] =============================");
-            info!(target: "consensus", "[{h:?}] Executing {holder:?} stake tx");
-            info!(target: "consensus", "[{h:?}] =============================");
-            self.execute_stake_tx(h, &stake_tx, &stake_params, current_slot).await?;
-        }
-
-        self.assert_trees(holders);
-
-        // Gather new staked owncoin
-        let staked_oc = self.gather_consensus_staked_owncoin(
-            holder,
-            &stake_params.output,
-            Some(stake_secret_key),
-        )?;
-
-        // Verify values match
-        assert!(oc.note.value == staked_oc.note.value);
-
-        Ok(staked_oc)
-    }
-}

+ 0 - 181
src/contract/test-harness/src/consensus_unstake.rs

@@ -1,181 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::time::Instant;
-
-use darkfi::{
-    tx::{ContractCallLeaf, Transaction, TransactionBuilder},
-    Result,
-};
-use darkfi_consensus_contract::{
-    client::unstake_v1::ConsensusUnstakeCallBuilder, ConsensusFunction,
-};
-use darkfi_money_contract::{
-    client::{unstake_v1::MoneyUnstakeCallBuilder, ConsensusOwnCoin, OwnCoin},
-    model::MoneyUnstakeParamsV1,
-    MoneyFunction, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
-};
-use darkfi_sdk::{
-    crypto::{MerkleNode, SecretKey, CONSENSUS_CONTRACT_ID, MONEY_CONTRACT_ID},
-    dark_tree::DarkTree,
-    ContractCall,
-};
-use darkfi_serial::{serialize, Encodable};
-use log::info;
-use rand::rngs::OsRng;
-
-use super::{Holder, TestHarness, TxAction};
-
-impl TestHarness {
-    pub fn unstake(
-        &mut self,
-        holder: &Holder,
-        staked_oc: &ConsensusOwnCoin,
-    ) -> Result<(Transaction, MoneyUnstakeParamsV1, SecretKey)> {
-        let wallet = self.holders.get(holder).unwrap();
-
-        let (burn_pk, burn_zkbin) =
-            self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1.to_string()).unwrap();
-        let (mint_pk, mint_zkbin) =
-            self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1.to_string()).unwrap();
-
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusUnstake).unwrap();
-
-        let timer = Instant::now();
-
-        // Building Consensus::Unstake params
-        let consensus_unstake_call_debris = ConsensusUnstakeCallBuilder {
-            owncoin: staked_oc.clone(),
-            tree: wallet.consensus_unstaked_merkle_tree.clone(),
-            burn_zkbin: burn_zkbin.clone(),
-            burn_pk: burn_pk.clone(),
-        }
-        .build()?;
-        let (
-            consensus_unstake_params,
-            consensus_unstake_proofs,
-            consensus_unstake_secret_key,
-            consensus_unstake_value_blind,
-        ) = (
-            consensus_unstake_call_debris.params,
-            consensus_unstake_call_debris.proofs,
-            consensus_unstake_call_debris.signature_secret,
-            consensus_unstake_call_debris.value_blind,
-        );
-
-        // Building Money::Unstake params
-        let money_unstake_call_debris = MoneyUnstakeCallBuilder {
-            owncoin: staked_oc.clone(),
-            recipient: self.holders.get(holder).unwrap().keypair.public,
-            value_blind: consensus_unstake_value_blind,
-            nullifier: consensus_unstake_params.input.nullifier,
-            merkle_root: consensus_unstake_params.input.merkle_root,
-            signature_public: consensus_unstake_params.input.signature_public,
-            mint_zkbin: mint_zkbin.clone(),
-            mint_pk: mint_pk.clone(),
-        }
-        .build()?;
-        let (money_unstake_params, money_unstake_proofs) =
-            (money_unstake_call_debris.params, money_unstake_call_debris.proofs);
-
-        // Building unstake tx
-        let mut data = vec![ConsensusFunction::UnstakeV1 as u8];
-        consensus_unstake_params.encode(&mut data)?;
-        let consensus_call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
-
-        let mut data = vec![MoneyFunction::UnstakeV1 as u8];
-        money_unstake_params.encode(&mut data)?;
-        let money_call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
-
-        let mut unstake_tx_builder = TransactionBuilder::new(
-            ContractCallLeaf { call: money_call, proofs: money_unstake_proofs },
-            vec![DarkTree::new(
-                ContractCallLeaf { call: consensus_call, proofs: consensus_unstake_proofs },
-                vec![],
-                None,
-                None,
-            )],
-        )?;
-        let mut unstake_tx = unstake_tx_builder.build()?;
-        let consensus_sigs = unstake_tx.create_sigs(&mut OsRng, &[consensus_unstake_secret_key])?;
-        let money_sigs = unstake_tx.create_sigs(&mut OsRng, &[consensus_unstake_secret_key])?;
-        unstake_tx.signatures = vec![consensus_sigs, money_sigs];
-        tx_action_benchmark.creation_times.push(timer.elapsed());
-
-        // Calculate transaction sizes
-        let encoded: Vec<u8> = serialize(&unstake_tx);
-        let size = ::std::mem::size_of_val(&*encoded);
-        tx_action_benchmark.sizes.push(size);
-        let base58 = bs58::encode(&encoded).into_string();
-        let size = ::std::mem::size_of_val(&*base58);
-        tx_action_benchmark.broadcasted_sizes.push(size);
-
-        Ok((unstake_tx, money_unstake_params, consensus_unstake_secret_key))
-    }
-
-    pub async fn execute_unstake_tx(
-        &mut self,
-        holder: &Holder,
-        tx: &Transaction,
-        params: &MoneyUnstakeParamsV1,
-        slot: u64,
-    ) -> Result<()> {
-        let wallet = self.holders.get_mut(holder).unwrap();
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusUnstake).unwrap();
-        let timer = Instant::now();
-
-        wallet.validator.add_transactions(&[tx.clone()], slot, true).await?;
-        wallet.money_merkle_tree.append(MerkleNode::from(params.output.coin.inner()));
-        tx_action_benchmark.verify_times.push(timer.elapsed());
-
-        Ok(())
-    }
-
-    // Execute an unstake transaction and gather unstaked coin
-    pub async fn execute_unstake(
-        &mut self,
-        holders: &[Holder],
-        holder: &Holder,
-        current_slot: u64,
-        unstake_request_oc: &ConsensusOwnCoin,
-    ) -> Result<OwnCoin> {
-        info!(target: "consensus", "[{holder:?}] ===================");
-        info!(target: "consensus", "[{holder:?}] Building unstake tx");
-        info!(target: "consensus", "[{holder:?}] ===================");
-        let (unstake_tx, unstake_params, _) = self.unstake(holder, unstake_request_oc)?;
-
-        for h in holders {
-            info!(target: "consensus", "[{h:?}] ===============================");
-            info!(target: "consensus", "[{h:?}] Executing {holder:?} unstake tx");
-            info!(target: "consensus", "[{h:?}] ===============================");
-            self.execute_unstake_tx(h, &unstake_tx, &unstake_params, current_slot).await?;
-        }
-
-        self.assert_trees(holders);
-
-        // Gather new unstaked owncoin
-        let unstaked_oc = self.gather_owncoin(holder, &unstake_params.output, None)?;
-
-        // Verify values match
-        assert!(unstake_request_oc.note.value == unstaked_oc.note.value);
-
-        Ok(unstaked_oc)
-    }
-}

+ 0 - 182
src/contract/test-harness/src/consensus_unstake_request.rs

@@ -1,182 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::time::Instant;
-
-use darkfi::{
-    tx::{ContractCallLeaf, Transaction, TransactionBuilder},
-    Result,
-};
-use darkfi_consensus_contract::{
-    client::unstake_request_v1::ConsensusUnstakeRequestCallBuilder, ConsensusFunction,
-};
-use darkfi_money_contract::{
-    client::ConsensusOwnCoin, model::ConsensusUnstakeReqParamsV1,
-    CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
-};
-use darkfi_sdk::{
-    crypto::{MerkleNode, SecretKey, CONSENSUS_CONTRACT_ID},
-    ContractCall,
-};
-use darkfi_serial::{serialize, Encodable};
-use log::info;
-use rand::rngs::OsRng;
-
-use super::{Holder, TestHarness, TxAction};
-
-impl TestHarness {
-    pub async fn unstake_request(
-        &mut self,
-        holder: &Holder,
-        slot: u64,
-        staked_oc: &ConsensusOwnCoin,
-    ) -> Result<(Transaction, ConsensusUnstakeReqParamsV1, SecretKey, SecretKey)> {
-        let wallet = self.holders.get(holder).unwrap();
-
-        let (burn_pk, burn_zkbin) =
-            self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1.to_string()).unwrap();
-
-        let (mint_pk, mint_zkbin) =
-            self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1.to_string()).unwrap();
-
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusUnstakeRequest).unwrap();
-        let epoch = wallet.validator.consensus.time_keeper.slot_epoch(slot);
-        let timer = Instant::now();
-
-        // Building Consensus::Unstake params
-        let unstake_request_call_debris = ConsensusUnstakeRequestCallBuilder {
-            owncoin: staked_oc.clone(),
-            epoch,
-            tree: wallet.consensus_staked_merkle_tree.clone(),
-            burn_zkbin: burn_zkbin.clone(),
-            burn_pk: burn_pk.clone(),
-            mint_zkbin: mint_zkbin.clone(),
-            mint_pk: mint_pk.clone(),
-        }
-        .build()?;
-
-        let (
-            unstake_request_params,
-            unstake_request_proofs,
-            unstake_request_output_keypair,
-            unstake_request_signature_secret_key,
-        ) = (
-            unstake_request_call_debris.params,
-            unstake_request_call_debris.proofs,
-            unstake_request_call_debris.keypair,
-            unstake_request_call_debris.signature_secret,
-        );
-
-        // Building unstake request tx
-        let mut data = vec![ConsensusFunction::UnstakeRequestV1 as u8];
-        unstake_request_params.encode(&mut data)?;
-        let call = ContractCall { contract_id: *CONSENSUS_CONTRACT_ID, data };
-        let mut unstake_request_builder = TransactionBuilder::new(
-            ContractCallLeaf { call, proofs: unstake_request_proofs },
-            vec![],
-        )?;
-        let mut unstake_request_tx = unstake_request_builder.build()?;
-        let sigs =
-            unstake_request_tx.create_sigs(&mut OsRng, &[unstake_request_signature_secret_key])?;
-        unstake_request_tx.signatures = vec![sigs];
-        tx_action_benchmark.creation_times.push(timer.elapsed());
-
-        // Calculate transaction sizes
-        let encoded: Vec<u8> = serialize(&unstake_request_tx);
-        let size = std::mem::size_of_val(&*encoded);
-        tx_action_benchmark.sizes.push(size);
-        let base58 = bs58::encode(&encoded).into_string();
-        let size = std::mem::size_of_val(&*base58);
-        tx_action_benchmark.broadcasted_sizes.push(size);
-
-        Ok((
-            unstake_request_tx,
-            unstake_request_params,
-            unstake_request_output_keypair.secret,
-            unstake_request_signature_secret_key,
-        ))
-    }
-
-    pub async fn execute_unstake_request_tx(
-        &mut self,
-        holder: &Holder,
-        tx: &Transaction,
-        params: &ConsensusUnstakeReqParamsV1,
-        slot: u64,
-    ) -> Result<()> {
-        let wallet = self.holders.get_mut(holder).unwrap();
-
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusUnstakeRequest).unwrap();
-
-        let timer = Instant::now();
-
-        wallet.validator.add_transactions(&[tx.clone()], slot, true).await?;
-        wallet.consensus_unstaked_merkle_tree.append(MerkleNode::from(params.output.coin.inner()));
-        tx_action_benchmark.verify_times.push(timer.elapsed());
-
-        Ok(())
-    }
-
-    // Execute an unstake request transaction and gather requested unstaked coin
-    pub async fn execute_unstake_request(
-        &mut self,
-        holders: &[Holder],
-        holder: &Holder,
-        current_slot: u64,
-        rewarded_staked_oc: &ConsensusOwnCoin,
-    ) -> Result<ConsensusOwnCoin> {
-        info!(target: "consensus", "[{holder:?}] ===========================");
-        info!(target: "consensus", "[{holder:?}] Building unstake request tx");
-        info!(target: "consensus", "[{holder:?}] ===========================");
-        let (
-            unstake_request_tx,
-            unstake_request_params,
-            unstake_request_output_secret_key,
-            _unstake_request_signature_secret_key,
-        ) = self.unstake_request(holder, current_slot, rewarded_staked_oc).await?;
-
-        for h in holders {
-            info!(target: "consensus", "[{h:?}] ==================================");
-            info!(target: "consensus", "[{h:?}] Executing {holder:?} unstake request tx");
-            info!(target: "consensus", "[{h:?}] ==================================");
-            self.execute_unstake_request_tx(
-                h,
-                &unstake_request_tx,
-                &unstake_request_params,
-                current_slot,
-            )
-            .await?;
-        }
-
-        self.assert_trees(holders);
-
-        // Gather new unstake request owncoin
-        let unstake_request_oc = self.gather_consensus_unstaked_owncoin(
-            holder,
-            &unstake_request_params.output,
-            Some(unstake_request_output_secret_key),
-        )?;
-
-        // Verify values match
-        assert!(rewarded_staked_oc.note.value == unstake_request_oc.note.value);
-
-        Ok(unstake_request_oc)
-    }
-}

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است