stakeholder.rs 14 KB

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