stakeholder.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. use async_executor::Executor;
  2. use async_trait::async_trait;
  3. use async_std::sync::Arc;
  4. use log::debug;
  5. use std::fmt;
  6. use std::time::Duration;
  7. use std::thread;
  8. use crate::zk::circuit::LeadContract;
  9. use crate::{
  10. consensus::{Block, BlockInfo,Metadata,StreamletMetadata,TransactionLeadProof},
  11. util::{
  12. time::Timestamp,
  13. clock::{Clock,Ticks},
  14. expand_path,
  15. },
  16. system::{Subscriber, SubscriberPtr, Subscription},
  17. crypto::{
  18. proof::{Proof, ProvingKey, VerifyingKey, },
  19. leadcoin::{LeadCoin},
  20. },
  21. blockchain::{Blockchain,Epoch,EpochConsensus},
  22. net::{P2p,Settings, SettingsPtr, Channel, ChannelPtr, Hosts, HostsPtr,MessageSubscription},
  23. tx::{Transaction},
  24. Result,Error,
  25. };
  26. use url::Url;
  27. use pasta_curves::{
  28. pallas,
  29. };
  30. use group::ff::PrimeField;
  31. #[derive(Debug)]
  32. pub struct SlotWorkspace
  33. {
  34. pub st : blake3::Hash,
  35. pub e: u64, // epoch index
  36. pub sl: u64, // absolute slot index
  37. pub txs: Vec<Transaction>, // unpublished block transactions
  38. pub metadata: Metadata,
  39. pub is_leader: bool,
  40. pub proof: Proof,
  41. pub block: BlockInfo,
  42. }
  43. impl Default for SlotWorkspace {
  44. fn default() -> Self {
  45. Self {st: blake3::hash(b""),
  46. e: 0,
  47. sl: 0,
  48. txs: vec![],
  49. is_leader: false,
  50. metadata: Metadata::default(),
  51. proof: Proof::default(),
  52. block: BlockInfo::default(),
  53. }
  54. }
  55. }
  56. impl SlotWorkspace {
  57. pub fn new_block(&self) -> (BlockInfo, blake3::Hash) {
  58. let sm = StreamletMetadata::new(vec!());
  59. let block = BlockInfo::new(self.st, self.e, self.sl, self.txs.clone(), self.metadata.clone(), sm);
  60. let hash = block.blockhash();
  61. (block, hash)
  62. }
  63. pub fn add_tx(& mut self, tx: Transaction) {
  64. self.txs.push(tx);
  65. }
  66. pub fn set_metadata(& mut self, md : Metadata) {
  67. self.metadata = md;
  68. }
  69. pub fn set_sl(&mut self, sl: u64) {
  70. self.sl = sl;
  71. }
  72. pub fn set_st(&mut self, st: blake3::Hash) {
  73. self.st = st;
  74. }
  75. pub fn set_e(&mut self, e: u64) {
  76. self.e = e;
  77. }
  78. pub fn set_proof(&mut self, proof: Proof) {
  79. self.proof = proof;
  80. }
  81. pub fn set_leader(&mut self, alead : bool) {
  82. self.is_leader = alead;
  83. }
  84. }
  85. pub struct Stakeholder
  86. {
  87. pub blockchain: Blockchain, // stakeholder view of the blockchain
  88. pub net : Arc<P2p>,
  89. pub clock : Clock,
  90. pub coins : Vec<LeadCoin>, // owned stakes
  91. pub epoch : Epoch, // current epoch
  92. pub epoch_consensus : EpochConsensus, // configuration for the epoch
  93. pub pk : ProvingKey,
  94. pub vk : VerifyingKey,
  95. pub playing: bool,
  96. pub workspace : SlotWorkspace,
  97. pub id: u8,
  98. //pub subscription: Subscription<Result<ChannelPtr>>,
  99. //pub chanptr : ChannelPtr,
  100. //pub msgsub : MessageSubscription::<BlockInfo>,
  101. }
  102. impl Stakeholder
  103. {
  104. pub async fn new(consensus: EpochConsensus, settings: Settings, rel_path: &str, id: u8, k: Option<u32>) -> Result<Self>
  105. {
  106. let path = expand_path(&rel_path).unwrap();
  107. debug!("opening db");
  108. let db = sled::open(&path)?;
  109. debug!("opend db");
  110. let ts = Timestamp::current_time();
  111. let genesis_hash = blake3::hash(b"");
  112. //TODO lisen and add transactions
  113. let bc = Blockchain::new(&db, ts, genesis_hash).unwrap();
  114. //TODO replace with const
  115. let eta = pallas::Base::one();
  116. let epoch = Epoch::new(consensus, eta);
  117. let lead_pk = ProvingKey::build(k.unwrap(), &LeadContract::default());
  118. let lead_vk = VerifyingKey::build(k.unwrap(), &LeadContract::default());
  119. let p2p = P2p::new(settings.clone()).await;
  120. //TODO
  121. let workspace = SlotWorkspace::default();
  122. //
  123. let clock = Clock::new(Some(consensus.get_epoch_len()), Some(consensus.get_slot_len()), Some(consensus.get_tick_len()), settings.peers);
  124. debug!("stakeholder constructed...");
  125. Ok(Self{blockchain: bc,
  126. net: p2p,
  127. clock: clock,
  128. coins: vec![], //constructed with empty coins for sake of simulation only
  129. // but should be populated from wallet db.
  130. epoch: epoch,
  131. epoch_consensus: consensus,
  132. pk: lead_pk,
  133. vk: lead_vk,
  134. playing: true,
  135. workspace: workspace,
  136. id: id,
  137. //subscription: subscription,
  138. //chanptr: chanptr,
  139. //msgsub: msg_sub,
  140. })
  141. }
  142. pub fn get_provkingkey(&self) -> ProvingKey {
  143. self.pk.clone()
  144. }
  145. pub fn get_verifyingkey(&self) -> VerifyingKey {
  146. self.vk.clone()
  147. }
  148. /// get list stakeholder peers on the p2p network for synchronization
  149. pub fn get_peers(&self) -> Vec<Url> {
  150. let settings : SettingsPtr = self.net.settings();
  151. settings.peers.clone()
  152. }
  153. /*
  154. fn new_block(&self) {
  155. //TODO initialize blocks in the epoch, and add coin commitment in genesis
  156. let block_info = BlockInfo::new(st, e, sl, txs, metadata, sm);
  157. self.block = block_info;
  158. }
  159. */
  160. fn init_network(&self) -> Result<()>{
  161. //TODO initialize exectutor
  162. //let exec = Arc<Executor<'_>>;
  163. let exec = Arc::new(Executor::new());
  164. exec.run(self.net.clone().start(exec.clone()));
  165. //self.net(exec);
  166. Ok(())
  167. }
  168. pub fn get_net(&self) -> Arc<P2p> {
  169. //TODO use P2p ptr not to overwrite wrappers
  170. self.net.clone()
  171. }
  172. /// add new blockinfo to the blockchain
  173. pub fn add_block(&self, block: BlockInfo) {
  174. let blocks = [block];
  175. self.blockchain.add(&blocks);
  176. }
  177. pub fn add_tx(&mut self, tx: Transaction)
  178. {
  179. self.workspace.add_tx(tx);
  180. }
  181. /// extract leader selection lottery randomness \eta
  182. /// it's the hash of the previous lead proof
  183. /// converted to pallas base
  184. pub fn get_eta(&self) -> pallas::Base
  185. {
  186. let last_proof_slot : u64 = 0;
  187. let proof_tx_hash = self.blockchain.get_last_proof_hash().unwrap();
  188. let mut bytes : [u8;32] = *proof_tx_hash.as_bytes();
  189. // read first 254 bits
  190. bytes[30] = 0;
  191. bytes[31] = 0;
  192. pallas::Base::from_repr(bytes).unwrap()
  193. }
  194. pub fn valid_block(&self, blk : BlockInfo) -> bool {
  195. //TODO implement
  196. true
  197. }
  198. /// listen to the network,
  199. /// for new transactions.
  200. pub fn sync_tx (&self) {
  201. //TODO
  202. }
  203. /// listen to the network channels,
  204. /// receive new messages, or blocks,
  205. /// validate the block proof, and the transactions,
  206. /// if so add the proof to metadata if stakeholder isn't the lead.
  207. pub async fn sync_block(&self) {
  208. let subscription : Subscription<Result<ChannelPtr>> = self.net.subscribe_channel().await;
  209. debug!("--> channel");
  210. let chanptr : ChannelPtr = subscription.receive().await.unwrap();
  211. debug!("--> received channel");
  212. //
  213. let message_subsytem = chanptr.get_message_subsystem();
  214. debug!("--> adding dispatcher to msg subsystem");
  215. message_subsytem.add_dispatch::<BlockInfo>().await;
  216. debug!("--> added");
  217. //TODO start channel if isn't started yet
  218. //let info = chanptr.get_info();
  219. //debug!("channel info: {}", info);
  220. debug!("--> subscribe msg_sub");
  221. let msg_sub : MessageSubscription::<BlockInfo> =
  222. chanptr.subscribe_msg::<BlockInfo>().await.expect("missing blockinfo");
  223. debug!("--> subscribed");
  224. let res = msg_sub.receive().await.unwrap();
  225. let blk : BlockInfo = (*res).to_owned();
  226. //TODO validate the block proof, and transactions.
  227. if self.valid_block(blk.clone()) {
  228. //TODO if valid only.
  229. self.blockchain.add(&[blk.clone()]);
  230. } else {
  231. debug!("received block is invalid!");
  232. }
  233. }
  234. pub async fn background(&mut self) {
  235. self.clock.sync().await;
  236. while self.playing {
  237. // clock ticks slot begins
  238. // initialize the epoch if it's the time
  239. // check for leadership
  240. match self.clock.ticks().await {
  241. Ticks::GENESIS{e, sl} => {
  242. //TODO (res) any initialization happening here?
  243. self.new_epoch();
  244. self.new_slot(e, sl);
  245. }
  246. Ticks::NEWEPOCH{e, sl} => {
  247. self.new_epoch();
  248. self.new_slot(e, sl);
  249. }
  250. Ticks::NEWSLOT{e, sl} => self.new_slot(e, sl),
  251. Ticks::TOCKS => {
  252. // slot is about to end.
  253. // sync, and validate.
  254. // no more transactions to be received/send to the end of slot.
  255. if self.workspace.is_leader {
  256. debug!("<<<--- [[[leadership won]]] --->>>");
  257. //craete block
  258. let (block_info, block_hash) = self.workspace.new_block();
  259. //add the block to the blockchain
  260. self.add_block(block_info.clone());
  261. let block : Block = Block::from(block_info.clone());
  262. // publish the block.
  263. self.net.broadcast(block);
  264. } else {
  265. //
  266. self.sync_block();
  267. }
  268. },
  269. Ticks::IDLE => {
  270. continue
  271. }
  272. Ticks::OUTOFSYNC => {
  273. // clock, and blockchain are out of sync
  274. self.clock.sync().await;
  275. self.sync_block();
  276. }
  277. }
  278. thread::sleep(Duration::from_millis(1000));
  279. }
  280. }
  281. pub fn to_string(&self) -> String {
  282. format!("stakeholder with id:{}", self.id.to_string())
  283. }
  284. /// on the onset of the epoch, layout the new the competing coins
  285. /// assuming static stake during the epoch, enforced by the commitment to competing coins
  286. /// in the epoch's gen2esis data.
  287. fn new_epoch(&mut self)
  288. {
  289. debug!("[new epoch] 4 {}", self);
  290. let eta = self.get_eta();
  291. let mut epoch = Epoch::new(self.epoch_consensus, self.get_eta());
  292. //TODO calculate total stake
  293. // create coin with absolute slot/epoch.
  294. let num_slots = self.workspace.sl;
  295. // total stake;
  296. let sigma = num_slots*reward;
  297. epoch.create_coins(); // set epoch interal fields working space with competing coins
  298. self.epoch = epoch.clone();
  299. }
  300. /// at the begining of the slot
  301. /// stakeholder need to play the lottery for the slot.
  302. /// FIXME if the stakeholder is not winning, staker can try different coins before,
  303. /// commiting it's coins, to maximize success, thus,
  304. /// the lottery proof need to be conditioned on the slot itself, and previous proof.
  305. /// this will encourage each potential leader to play with honesty.
  306. fn new_slot(&mut self, e: u64, sl: u64)
  307. {
  308. debug!("[new slot] 4 {}\ne:{}, sl:{}", self, e, sl);
  309. let EMPTY_PTR = blake3::hash(b"");
  310. let st : blake3::Hash = if e>0 || (e==0&&sl>0) {
  311. self.workspace.block.blockhash()
  312. } else {
  313. EMPTY_PTR
  314. };
  315. let is_leader : bool = self.epoch.is_leader(sl);
  316. // if is leader create proof
  317. let proof = if is_leader {
  318. self.epoch.get_proof(sl, &self.pk.clone())
  319. } else {
  320. Proof::new(vec![])
  321. };
  322. // set workspace
  323. self.workspace.set_sl(sl);
  324. self.workspace.set_e(e);
  325. self.workspace.set_st(st);
  326. self.workspace.set_leader(is_leader);
  327. self.workspace.set_proof(proof.clone());
  328. //
  329. if is_leader {
  330. let metadata = Metadata::new(Timestamp::current_time(),
  331. self.get_eta().to_repr(),
  332. TransactionLeadProof::from(proof.clone()));
  333. self.workspace.set_metadata(metadata);
  334. }
  335. }
  336. }
  337. impl fmt::Display for Stakeholder {
  338. fn fmt(&self, formater : &mut fmt::Formatter) -> fmt::Result {
  339. formater.write_fmt(format_args!("stakeholder with id: {}", self.id))
  340. }
  341. }