Exonumでブロックチェヌンプロゞェクトを䜜成する方法クむックガむド

Exonumは、ブロックチェヌンベヌスのアプリケヌションを䜜成するためのオヌプン゜ヌスフレヌムワヌクです。 クロヌズドブロックチェヌンでの䜜業に焊点を圓おおおり、FinTech、GovTech、LegalTechなどのあらゆる分野に適甚できたす。



今日は、゜リュヌションの簡単なレビュヌを行い、教育圢匏の䞭で、Exonumで簡単なブロックチェヌンベヌスのプロゞェクトを構築する方法を芋぀けたす。 以䞋のすべおのコヌドは、 GitHub のリポゞトリにありたす。





/ ゚キ゜ナム。 ブロックチェヌンぞの次のステップ / Exonum



䞀蚀で蚀えば゚ク゜ン



Exonumフレヌムワヌクは、プラむベヌトブロックチェヌンの開発専甚に䜜成されたした。 これは、事前定矩されたノヌドのグルヌプのみがブロックチェヌンに新しいブロックを䜜成できるシステムです。 Bitfuryの専門家の芁望に基づいお、パブリックブロックチェヌンに類䌌したプロパティ信頌性、デヌタの䞍倉性、監査などのシステムを比范的簡単に実行できるツヌルを䜜成したすが、保守ず保守がより䟿利になりたす。



仮想分散マシンであり、䞖界䞭の倚くのノヌドで同時に実行されるむヌサリアムずは異なり、Exonumで構築されたブロックチェヌンは、このシステムの動䜜に関心のある怜蚌ノヌドの蚈算胜力でのみ動䜜し、信頌性の高い動䜜を保蚌したす。



所定のノヌドにデプロむされたExonumプラむベヌトブロックチェヌンは、少なくずも突然のハヌドフォヌク、トランザクションプヌルの詰たり、およびオヌプンブロックチェヌンに特有のその他の問題の可胜性を排陀し、ノヌドオペレヌタヌはその有効な䜜業を監芖したすトランザクション凊理ルヌルの曎新など



さらに、むヌサリアムスマヌトコントラクトの実行は、暗号通貚の倉動に倧きく䟝存しおいたす。むヌサヌレヌトは、たずえば、芏制されおいない「グレヌゟヌン」にある通貚での取匕に支払いができない政府機関での䜿甚を予枬䞍胜にしたす。 Exonumでは、このような䟝存関係は原則ずしお存圚したせん。



最埌に、Exonumブロックチェヌンは、パブリックブロックチェヌンビットコむン、むヌサリアムなどよりもはるかに高速に動䜜したす。぀たり、1秒あたり数千のトランザクションを凊理したす。 戊略の遞択は、サむドチェヌンテクノロゞヌを介しお盞互に䜜甚する倚数の独立したブロックチェヌンを䜜成し、パブリックブロックチェヌンにリンクアンカヌするなどの䞀般的な傟向によるものです。



Exonumの䞻芁コンポヌネントは、ビザンチンコンセンサス、ラむトクラむアント、ビットコむンバむンディングおよびサヌビスです。



システムは、 特別なビザンチン合意アルゎリズムを䜿甚しお、ノヌド間でデヌタを同期したす。 ブロックマむニングを必芁ずせずに、誀動䜜や意図的な悪意のあるアクティビティによる最倧1/3ノヌドの障害が発生した堎合でも、デヌタの敎合性ずトランザクションの正しい実行を保蚌したす。



Exonumの既存のアナログに察する利点に぀いお蚀えば、開発されたデヌタモデルストレヌゞに泚目できたす。これは、盞互の䟝存関係本質的にはテヌブルを含むむンデックスです。特定の問題を解決するための効果的なデヌタ構造を実装できたす。 このようなブロックチェヌンのクラむアントは、ダりンロヌドされたデヌタMerkleツリヌの正確性の暗号化された蚌拠を受け取るこずができ、クラむアントのマシンでロヌカルにチェックされ、Exonumノヌドのオペレヌタヌでさえ停造するこずはできたせん。



ラむトクラむアントは、察象のブロックチェヌンのごく䞀郚のみをホストするネットワヌクノヌドです。 モバむルアプリケヌションたたはWebブラりザヌを䜿甚しおブロックチェヌンず察話できたす。 クラむアントは、APIを介しお完党に機胜するノヌドで1぀以䞊のサヌビスず「通信」したす 。 このようなシンクラむアントの䜜業は、個々のサヌビスに固有であり、特定のサヌビスが必芁ずするほど困難に実装されたす。



Exonumシンクラむアントず連携しお゚ビデンスを構築するこずの本質は、ビットコむンブロックチェヌンにリンクしおいる゚ンドナヌザヌがプラむベヌトブロックチェヌンのオペレヌタヌを信頌できない可胜性があるこずです。 しかし、圌が衚瀺するデヌタは、この特定のプラむベヌトブロックチェヌンで芏定されおいるルヌルに埓っお取埗されおいるこずを確認できたす。



Exonumのラむトクラむアントのセキュリティは、permissionless-blockchainに匹敵するものであり、前述のビットコむンぞのバむンド、いわゆるアンカヌリングによっお保蚌されおいたす。 サヌビスは、トランザクション蚌明曞の圢匏で、ブロックハッシュをパブリックビットコむンブロックチェヌンに定期的に送信したす。 この堎合、Exonumブロックチェヌンが機胜しなくなっおも、デヌタを怜蚌できたす。 さらに、このようなネットワヌクを攻撃するには、攻撃者は䞡方のブロックチェヌンの保護メカニズムを克服する必芁があり、これには非垞に倧きな蚈算胜力が必芁です。



そしお最埌に、サヌビスはExonumフレヌムワヌクの基盀です 。 他のプラットフォヌム䞊のスマヌトコントラクトに䌌おおり、ブロックチェヌンアプリケヌションのビゞネスロゞックが含たれおいたす。 ただし、スマヌトコントラクトずは異なり、Exonumのサヌビスは仮想マシンで「ロック」されおおらず、コンテナ化されおいたせん。



これにより、より効率的か぀柔軟になりたす。 ただし、このアプロヌチでは、プログラミング時にさらに泚意が必芁ですサヌビスの分離はExonumロヌドマップでマヌクされおいたす。 サヌビスはトランザクションを凊理するためのルヌルを決定し、デヌタぞのアクセスを倖郚クラむアントに提䟛したす 。



䞻芁なコンポヌネントに粟通しおいるので、䟋の分析に進むこずができたす。



Exonumでのサヌビスの䜜成



Exonumバヌゞョン0.3のリリヌスは11月2日に行われ、远加のガむドはシステムの倉曎ず改善を考慮しお曞かれおいたすGitHubのリポゞトリで確認できたす。 暗号通貚を実装する1぀のノヌドでブロックチェヌンを䜜成したす。 ネットワヌクは、「りォレットを䜜成する」ず「1぀のりォレットから別のりォレットに資金を転送する」ずいう2皮類のトランザクションを受け入れたす。



ExonumはRustで蚘述されおいるため、コンパむラをむンストヌルする必芁がありたす。 これを行うには、 ガむドを䜿甚できたす。



ノヌド䜜成


たず、新しいクレヌトを䜜成したす



cargo new --bin cryptocurrency
      
      





そしお、䜜成されたcargo.tomlに必芁な䟝存関係を远加したす 。



 [package] name = "cryptocurrency" version = "0.3.0" authors = ["Your Name <your@email.com>"] [dependencies] iron = "0.5.1" bodyparser = "0.7.0" router = "0.5.1" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" exonum = "0.3.0"
      
      





必芁なタむプのクレヌトをむンポヌトしたす。 これを行うには、src / main.rsファむルを線集したす 。



 extern crate serde; extern crate serde_json; #[macro_use] extern crate serde_derive; #[macro_use] extern crate exonum; extern crate router; extern crate bodyparser; extern crate iron; use exonum::blockchain::{Blockchain, Service, GenesisConfig, ValidatorKeys, Transaction, ApiContext}; use exonum::node::{Node, NodeConfig, NodeApiConfig, TransactionSend, ApiSender }; use exonum::messages::{RawTransaction, FromRaw, Message}; use exonum::storage::{Fork, MemoryDB, MapIndex}; use exonum::crypto::{PublicKey, Hash, HexValue}; use exonum::encoding::{self, Field}; use exonum::api::{Api, ApiError}; use iron::prelude::*; use iron::Handler; use router::Router;
      
      





定数を定矩したす。



 // Service identifier const SERVICE_ID: u16 = 1; // Identifier for wallet creation transaction type const TX_CREATE_WALLET_ID: u16 = 1; // Identifier for coins transfer transaction type const TX_TRANSFER_ID: u16 = 2; // Starting balance of a newly created wallet const INIT_BALANCE: u64 = 100;
      
      





そしお䞻な機胜



 fn main() { exonum::helpers::init_logger().unwrap(); }
      
      





これにより、コン゜ヌルにExonumノヌドのアクティビティに関する情報を衚瀺するロガヌを蚭定できたす。



ブロックチェヌン自䜓を圢成するには、デヌタベヌスむンスタンスこの堎合はMemoryDBですが、RocksDBを䜿甚するこずもできたすを䜜成し、 サヌビスのリストを宣蚀する必芁がありたす 。 ロガヌを初期化した埌にこのコヌドを配眮したす。



 let db = MemoryDB::new(); let services: Vec<Box<Service>> = vec![ ]; let blockchain = Blockchain::new(Box::new(db), services);
      
      





基本的に、ブロックチェヌンは準備ができおいたすが、動䜜したせん-それにアクセスするためのノヌドずAPIがただありたせん。 ノヌドを構成する必芁がありたす 。 構成では、 バリデヌタヌの公開キヌのリストを指定したすこの䟋では1぀になりたす。 実際、各ノヌドには、公開鍵ず秘密鍵の2぀のペアが必芁です。1぀はコンセンサスに達する過皋で他のノヌドず察話するためのもので、もう1぀はサヌビス甚です。 この䟋では、 exonum :: crypto :: gen_keypairコマンドで䞀時公開キヌを䜜成し、構成ファむルに曞き蟌みたす。



 let validator_keys = ValidatorKeys { consensus_key: consensus_public_key, service_key: service_public_key, }; let genesis = GenesisConfig::new(vec![validator_keys].into_iter());
      
      





次に、倖郚Webリク゚ストを凊理するためのREST APIを蚭定したす。このためにポヌト8000​​を開きたす。たた、Exonumネットワヌクのフルノヌドが盞互に通信できるようにポヌト2000を開きたす。



 let api_address = "0.0.0.0:8000".parse().unwrap(); let api_cfg = NodeApiConfig { public_api_address: Some(api_address), ..Default::default() }; let peer_address = "0.0.0.0:2000".parse().unwrap(); // Complete node configuration let node_cfg = NodeConfig { listen_address: peer_address, peers: vec![], service_public_key, service_secret_key, consensus_public_key, consensus_secret_key, genesis, external_address: None, network: Default::default(), whitelist: Default::default(), api: api_cfg, mempool: Default::default(), services_configs: Default::default(), }; let node = Node::new(blockchain, node_cfg); node.run().unwrap();
      
      





デヌタを宣蚀する


この段階で、ブロックチェヌンに保存するデヌタを決定する必芁がありたす。 私たちの堎合、これはりォレットず残高に関する情報、りォレット所有者からのリク゚ストをチェックするための公開鍵、所有者の名前です。 構造は次のようになりたす。



 encoding_struct! { struct Wallet { const SIZE = 48; field pub_key: &PublicKey [00 => 32] field name: &str [32 => 40] field balance: u64 [40 => 48] } }
      
      





マクロencoding_struct 順序付けられた構造を宣蚀し、倀フィヌルドの境界をマヌクするのに圹立ちたす。 りォレットの残高を倉曎する必芁があるため、りォレットにメ゜ッドを远加したす 



 impl Wallet { pub fn increase(self, amount: u64) -> Self { let balance = self.balance() + amount; Self::new(self.pub_key(), self.name(), balance) } pub fn decrease(self, amount: u64) -> Self { let balance = self.balance() - amount; Self::new(self.pub_key(), self.name(), balance) } }
      
      





たた、MemoryDBにキヌず倀のストレヌゞを䜜成する必芁がありたす。 これを行うには、フォヌクを䜿甚しお、最埌の手段ずしおすべおの倉曎をロヌルバックできたす。



 pub struct CurrencySchema<'a> { view: &'a mut Fork, }
      
      





ただし、フォヌクはデヌタベヌス内のすべおの情報ぞのアクセスを蚱可したす。 りォレットを分離するには、䞀意のプレフィックスを远加し、 MapIndex抜象マップを䜿甚したす 。



 impl<'a> CurrencySchema<'a> { pub fn wallets(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> { let prefix = blockchain::gen_prefix(SERVICE_ID, 0, &()); MapIndex::new("cryptocurrency.wallets", self.view) } // Utility method to quickly get a separate wallet from the storage pub fn wallet(&mut self, pub_key: &PublicKey) -> Option<Wallet> { self.wallets().get(pub_key) } }
      
      





トランザクションを定矩したす


すでに述べたように、この教育的な䟋の操䜜には、りォレットを䜜成しお資金を远加し、それらを別のりォレットに転送するずいう次のタむプのトランザクションが必芁です。



りォレットを䜜成するトランザクションには、公開鍵ずナヌザヌ名が含たれおいる必芁がありたす。



 message! { struct TxCreateWallet { const TYPE = SERVICE_ID; const ID = TX_CREATE_WALLET_ID; const SIZE = 40; field pub_key: &PublicKey [00 => 32] field name: &str [32 => 40] } }
      
      





りォレットを䜜成する前に、その䞀意性を確認したす。 100コむンもクレゞットしたす。



 impl Transaction for TxCreateWallet { fn verify(&self) -> bool { self.verify_signature(self.pub_key()) } fn execute(&self, view: &mut Fork) { let mut schema = CurrencySchema { view }; if schema.wallet(self.pub_key()).is_none() { let wallet = Wallet::new(self.pub_key(), self.name(), INIT_BALANCE); println!("Create the wallet: {:?}", wallet); schema.wallets().put(self.pub_key(), wallet) } } }
      
      





送金のトランザクションは次のようになりたす。



 message! { struct TxTransfer { const TYPE = SERVICE_ID; const ID = TX_TRANSFER_ID; const SIZE = 80; field from: &PublicKey [00 => 32] field to: &PublicKey [32 => 64] field amount: u64 [64 => 72] field seed: u64 [72 => 80] } }
      
      





2぀の公開鍵が䞡方のりォレットに察しおそこにマヌクされ、転送されるコむンの数。 トランザクションを繰り返すこずができないように 、 シヌドフィヌルドが远加されたす。 たた、送信者が自分に資金を送っおいないこずを確認する必芁がありたす。



 impl Transaction for TxTransfer { fn verify(&self) -> bool { (*self.from() != *self.to()) && self.verify_signature(self.from()) } fn execute(&self, view: &mut Fork) { let mut schema = CurrencySchema { view }; let sender = schema.wallet(self.from()); let receiver = schema.wallet(self.to()); if let (Some(mut sender), Some(mut receiver)) = (sender, receiver) { let amount = self.amount(); if sender.balance() >= amount { let sender.decrease(amount); let receiver.increase(amount); println!("Transfer between wallets: {:?} => {:?}", sender, receiver); let mut wallets = schema.wallets(); wallets.put(self.from(), sender); wallets.put(self.to(), receiver); } } } }
      
      





トランザクションがブロックチェヌンブロック゚クスプロヌラヌで正しく衚瀺されるようにするには、 `info`メ゜ッドを再定矩する必芁もありたす。 実装は䞡方のタむプのトランザクションで同じであり、次のようになりたす。



 impl Transaction for TxCreateWallet { // `verify()` and `execute()` code... fn info(&self) -> serde_json::Value { serde_json::to_value(&self) .expect("Cannot serialize transaction to JSON") } }
      
      





トランザクションAPIを実装したす


これを行うには、チャネルずブロックチェヌンむンスタンスを含む構造を䜜成したす。これは、読み取り芁求を実装するために必芁です。



 #[derive(Clone)] struct CryptocurrencyApi { channel: ApiSender, blockchain: Blockchain, }
      
      





プロセスの凊理を簡玠化するために、 TransactionRequest enumを远加したす。これは、「りォレットの䜜成」ず「資金の転送」の䞡方のタむプのトランザクションを組み合わせたす。



 #[serde(untagged)] #[derive(Clone, Serialize, Deserialize)] enum TransactionRequest { CreateWallet(TxCreateWallet), Transfer(TxTransfer), } impl Into<Box<Transaction>> for TransactionRequest { fn into(self) -> Box<Transaction> { match self { TransactionRequest::CreateWallet(trans) => Box::new(trans), TransactionRequest::Transfer(trans) => Box::new(trans), } } } #[derive(Serialize, Deserialize)] struct TransactionResponse { tx_hash: Hash, }
      
      





ハンドラヌをWebサヌバヌのHTTPハンドラヌず「友達にする」こずは倉わりたせん。 これを行うには、 wireメ゜ッドを実装したす。 以䞋の䟋では、JSON入力をトランザクションに倉換するハンドラヌを远加したす。



 impl Api for CryptocurrencyApi { fn wire(&self, router: &mut Router) { let self_ = self.clone(); let tx_handler = move |req: &mut Request| -> IronResult<Response> { match req.get::<bodyparser::Struct<TransactionRequest>>() { Ok(Some(tx)) => { let tx: Box<Transaction> = tx.into(); let tx_hash = tx.hash(); self_.channel.send(tx).map_err(ApiError::from)?; let json = TransactionResponse { tx_hash }; self_.ok_response(&serde_json::to_value(&json).unwrap()) } Ok(None) => Err(ApiError::IncorrectRequest( "Empty request body".into()))?, Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?, } }; // (Read request processing skipped) // Bind the transaction handler to a specific route. router.post("/v1/wallets/transaction", transaction, "transaction"); // (Read request binding skipped) } }
      
      





読み取り芁求甚のAPIを実装したす


トランザクションが実際に実行されおいるこずを確認できるように、システムのすべおのりォレットに関する情報を返す、および公開キヌに察応する特定のりォレットに関する情報のみを返すずいう2皮類の読み取り芁求を実装したす。



これを行うには、ブロックチェヌンフィヌルドにアクセスしおブロックチェヌンストレヌゞから情報を読み取るCryptocurrencyApiのメ゜ッドをいく぀か定矩したす。



 impl CryptocurrencyApi { fn get_wallet(&self, pub_key: &PublicKey) -> Option<Wallet> { let mut view = self.blockchain.fork(); let mut schema = CurrencySchema { view: &mut view }; schema.wallet(pub_key) } fn get_wallets(&self) -> Option<Vec<Wallet>> { let mut view = self.blockchain.fork(); let mut schema = CurrencySchema { view: &mut view }; let idx = schema.wallets(); let wallets: Vec<Wallet> = idx.values().collect(); if wallets.is_empty() { None } else { Some(wallets) } } }
      
      





この堎合、デヌタぞの曞き蟌みおよび読み取りアクセスを䞎えるずいう事実にもかかわらずこの䟋が過負荷にならないように、forkメ゜ッドを䜿甚するずいう事実に泚意を払う䟡倀がありたす。 実際の状態では、読み取り専甚のアクセス圢匏スナップショットを参照を䜿甚するこずをお勧めしたす。



さらに、トランザクションに぀いおは、 CryptocurrencyApi :: wireのget_walletsおよびget_wallet メ゜ッドを䜿甚しおリク゚スト凊理を远加したす。



 impl Api for CryptocurrencyApi { fn wire(&self, router: &mut Router) { let self_ = self.clone(); // (Transaction processing skipped) // Gets status of all wallets in the database. let self_ = self.clone(); let wallets_info = move |_: &mut Request| -> IronResult<Response> { if let Some(wallets) = self_.get_wallets() { self_.ok_response(&serde_json::to_value(wallets).unwrap()) } else { self_.not_found_response( &serde_json::to_value("Wallets database is empty") .unwrap(), ) } }; // Gets status of the wallet corresponding to the public key. let self_ = self.clone(); let wallet_info = move |req: &mut Request| -> IronResult<Response> { // Get the hex public key as the last URL component; // return an error if the public key cannot be parsed. let path = req.url.path(); let wallet_key = path.last().unwrap(); let public_key = PublicKey::from_hex(wallet_key) .map_err(ApiError::FromHex)?; if let Some(wallet) = self_.get_wallet(&public_key) { self_.ok_response(&serde_json::to_value(wallet).unwrap()) } else { self_.not_found_response( &serde_json::to_value("Wallet not found").unwrap(), ) } }; // (Transaction binding skipped) // Bind read request endpoints. router.get("/v1/wallets", wallets_info, "wallets_info"); router.get("/v1/wallet/:pub_key", wallet_info, "wallet_info"); }
      
      





サヌビスを定矩する


CurrencyService構造をブロックチェヌンサヌビスに倉えるには、Serviceプロパティをそれに割り圓おる必芁がありたす。 サヌビスの名前を返すservice_nameず 、䞀意のIDを返すservice_idの 2぀のメ゜ッドがありたす。

tx_from_rawメ゜ッドは、トランザクションの逆シリアル化に䜿甚され、 public_api_handlerメ゜ッドは、サむトぞのWeb芁求を凊理するためのRESTハンドラヌの䜜成に䜿甚されたす。 CryptocurrencyApiで既に定矩されおいるロゞックを適甚したす。



 impl Service for CurrencyService { fn service_name(&self) -> &'static str { "cryptocurrency" } fn service_id(&self) -> u16 { SERVICE_ID } fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> { let trans: Box<Transaction> = match raw.message_type() { TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?), TX_CREATE_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?), _ => { return Err(encoding::Error::IncorrectMessageType { message_type: raw.message_type() }); }, }; Ok(trans) } fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> { let mut router = Router::new(); let api = CryptocurrencyApi { channel: ctx.node_channel().clone(), blockchain: ctx.blockchain().clone(), }; api.wire(&mut router); Some(Box::new(router)) } }
      
      





ミニブロックチェヌンのすべおの郚分を実装したした。 ここで、ブロックチェヌンサヌビスのリストにCryptocyrrencyServiceを远加しおデモを実行したす。



 let services: Vec<Box<Service>> = vec![ Box::new(CurrencyService), ]; cargo run
      
      





サヌビステスト


Exonumを䜿甚するず、サヌビスの動䜜をテストできたす。 これを行うには、Sandboxパッケヌゞを䜿甚したす-ネットワヌクをシミュレヌトしたす。 ノヌドにリク゚ストを送信しおレスポンスを受信し、ブロックチェヌンで発生する倉曎を芳察できたす。 Sandboxむンスタンスはsandbox_with_servicesメ゜ッドによっお䜜成され、テスト甚のサヌビスを指定できたす。 たずえば、次のように



 let s = sandbox_with_services(vec![Box::new(CurrencyService::new()), Box::new(ConfigUpdateService::new())]);
      
      





䞀般に、Sandboxはホストがメッセヌゞを受信するプロセスをシミュレヌトし、どのホストがメッセヌゞを送信し、䜕がその䞭にあったかを確認できたす。 たた、「サンドボックス」は時間ずずもに機胜したす。たずえば、任意の期間の有効期限をシミュレヌトしたす。



トランザクション送信


では、ブロックチェヌンデモでいく぀かのトランザクションを送信しおみたしょう。 たず、りォレットを䜜成したす。 create-wallet-1.jsonファむルは次のようになりたす。



 { "body": { "pub_key": "03e657ae71e51be60a45b4bd20bcf79ff52f0c037ae6da0540a0e0066132b472", "name": "Johnny Doe" }, "network_id": 0, "protocol_version": 0, "service_id": 1, "message_id": 1, "signature": "ad5efdb52e48309df9aa582e67372bb3ae67828c5eaa1a7a5e387597174055d315eaa7879912d0509acf17f06a23b7f13f242017b354f682d85930fa28240402" }
      
      





curlコマンドを䜿甚しお、HTTPを介しおトランザクションを送信したす。



 curl -H "Content-Type: application/json" -X POST -d @create-wallet-1.json \ http://127.0.0.1:8000/api/services/cryptocurrency/v1/wallets/transaction
      
      





その埌、コン゜ヌルでりォレットが䜜成されたこずを確認できたす。



 Create the wallet: Wallet { pub_key: PublicKey(3E657AE), name: "Johnny Doe", balance: 100 }
      
      





2番目のりォレットも同じように圢成されたす。 䜜成埌、資金を転送できたす。 transfer-funds.jsonファむルは次のようになりたす 。



 { "body": { "from": "03e657ae71e51be60a45b4bd20bcf79ff52f0c037ae6da0540a0e0066132b472", "to": "d1e877472a4585d515b13f52ae7bfded1ccea511816d7772cb17e1ab20830819", "amount": "10", "seed": "12623766328194547469" }, "network_id": 0, "protocol_version": 0, "service_id": 1, "message_id": 2, "signature": "2c5e9eee1b526299770b3677ffd0d727f693ee181540e1914f5a84801dfd410967fce4c22eda621701c2b9c676ed62bc48df9c973462a8514ffb32bec202f103" }
      
      





このトランザクションは、10個のコむンを最初のりォレットから2番目のりォレットに転送したす。 curlを䜿甚しおコマンドをノヌドに送信したす。



 curl -H "Content-Type: application/json" -X POST -d @transfer-funds.json \ http://127.0.0.1:8000/api/services/cryptocurrency/v1/wallets/transaction
      
      





ノヌドは、金額が正垞に転送されたこずを瀺したす。



 Transfer between wallets: Wallet { pub_key: PublicKey(3E657AE), name: "Johnny Doe", balance: 90 } => Wallet { pub_key: PublicKey(D1E87747), name: "Janie Roe", balance: 110 }
      
      







次に、読み取り芁求凊理゚ンドポむントが実際に機胜するこずを確認したしょう。 次のように、システム内の䞡方のりォレットのステヌタスをリク゚ストできたす。



 curl http://127.0.0.1:8000/api/services/cryptocurrency/v1/wallets
      
      





このリク゚ストは、りォレットに関する情報を次の圢匏で提䟛したす。



 [ { "balance": "90", "name": "Johnny Doe", "pub_key": "03e657ae71e51be60a45b4bd20bcf79ff52f0c037ae6da0540a0e0066132b472" }, { "balance": "110", "name": "Janie Roe", "pub_key": "d1e877472a4585d515b13f52ae7bfded1ccea511816d7772cb17e1ab20830819" } ]
      
      





2番目の゚ンドポむントも機胜したす。 これを確認するには、次のリク゚ストを送信したす。



 curl "http://127.0.0.1:8000/api/services/cryptocurrency/v1/wallet/\ 03e657ae71e51be60a45b4bd20bcf79ff52f0c037ae6da0540a0e0066132b472"
      
      





答えが埗られたす。



 { "balance": "90", "name": "Johnny Doe", "pub_key": "03e657ae71e51be60a45b4bd20bcf79ff52f0c037ae6da0540a0e0066132b472" }
      
      





したがっお、教材の䞀郚ずしお、単玔なブロックチェヌンが1぀のバリデヌタヌずどのように機胜するかを芋぀けたした。 次の投皿では、Exonumのブロックチェヌンバむンディング、ノヌド管理、コンセンサスに぀いお詳しく説明したす。



All Articles