add get_epoch_vote_accounts rpc (#4317)
* add get_epoch_vote_accounts rpc * fixups * documentation and type updates
This commit is contained in:
parent
1acfcf3acf
commit
ead15d294e
|
@ -30,6 +30,7 @@ Methods
|
||||||
* [getSlotLeader](#getslotleader)
|
* [getSlotLeader](#getslotleader)
|
||||||
* [getNumBlocksSinceSignatureConfirmation](#getnumblockssincesignatureconfirmation)
|
* [getNumBlocksSinceSignatureConfirmation](#getnumblockssincesignatureconfirmation)
|
||||||
* [getTransactionCount](#gettransactioncount)
|
* [getTransactionCount](#gettransactioncount)
|
||||||
|
* [getEpochVoteAccounts](#getepochvoteaccounts)
|
||||||
* [requestAirdrop](#requestairdrop)
|
* [requestAirdrop](#requestairdrop)
|
||||||
* [sendTransaction](#sendtransaction)
|
* [sendTransaction](#sendtransaction)
|
||||||
* [startSubscriptionChannel](#startsubscriptionchannel)
|
* [startSubscriptionChannel](#startsubscriptionchannel)
|
||||||
|
@ -274,6 +275,39 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### getEpochVoteAccounts
|
||||||
|
Returns the account info and associated stake for all the voting accounts in the current epoch.
|
||||||
|
|
||||||
|
##### Parameters:
|
||||||
|
None
|
||||||
|
|
||||||
|
##### Results:
|
||||||
|
An array consisting of vote accounts:
|
||||||
|
* `string` - the vote account's Pubkey as base-58 encoded string
|
||||||
|
* `integer` - the stake, in lamports, delegated to this vote account
|
||||||
|
* `VoteState` - the vote account's state
|
||||||
|
|
||||||
|
Each VoteState will be a JSON object with the following sub fields:
|
||||||
|
|
||||||
|
* `votes`, array of most recent vote lockouts
|
||||||
|
* `node_id`, the pubkey of the node that votes using this account
|
||||||
|
* `authorized_voter_id`, the pubkey of the authorized vote signer for this account
|
||||||
|
* `commission`, a 32-bit integer used as a fraction (commission/MAX_U32) for rewards payout
|
||||||
|
* `root_slot`, the most recent slot this account has achieved maximum lockout
|
||||||
|
* `credits`, credits accrued by this account for reaching lockouts
|
||||||
|
|
||||||
|
##### Example:
|
||||||
|
```bash
|
||||||
|
// Request
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochVoteAccounts"}' http://localhost:8899
|
||||||
|
|
||||||
|
// Result
|
||||||
|
{"jsonrpc":"2.0","result":[[[84,115,89,23,41,83,221,72,58,23,53,245,195,188,140,161,242,189,200,164,139,214,12,180,84,161,28,151,24,243,159,125],10000000,{"authorized_voter_id":[84,115,89,23,41,83,221,72,58,23,53,245,195,188,140,161,242,189,200,164,139,214,12,180,84,161,28,151,24,243,159,125],"commission":0,"credits":0,"node_id":[49,139,227,211,47,39,69,86,131,244,160,144,228,169,84,143,142,253,83,81,212,110,254,12,242,71,219,135,30,60,157,213],"root_slot":null,"votes":[{"confirmation_count":1,"slot":0}]}]],"id":1}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### requestAirdrop
|
### requestAirdrop
|
||||||
Requests an airdrop of lamports to a Pubkey
|
Requests an airdrop of lamports to a Pubkey
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ pub enum RpcRequest {
|
||||||
GetRecentBlockhash,
|
GetRecentBlockhash,
|
||||||
GetSignatureStatus,
|
GetSignatureStatus,
|
||||||
GetSlotLeader,
|
GetSlotLeader,
|
||||||
|
GetEpochVoteAccounts,
|
||||||
GetStorageBlockhash,
|
GetStorageBlockhash,
|
||||||
GetStorageSlot,
|
GetStorageSlot,
|
||||||
GetStoragePubkeysForSlot,
|
GetStoragePubkeysForSlot,
|
||||||
|
@ -39,6 +40,7 @@ impl RpcRequest {
|
||||||
RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
|
RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
|
||||||
RpcRequest::GetSignatureStatus => "getSignatureStatus",
|
RpcRequest::GetSignatureStatus => "getSignatureStatus",
|
||||||
RpcRequest::GetSlotLeader => "getSlotLeader",
|
RpcRequest::GetSlotLeader => "getSlotLeader",
|
||||||
|
RpcRequest::GetEpochVoteAccounts => "getEpochVoteAccounts",
|
||||||
RpcRequest::GetStorageBlockhash => "getStorageBlockhash",
|
RpcRequest::GetStorageBlockhash => "getStorageBlockhash",
|
||||||
RpcRequest::GetStorageSlot => "getStorageSlot",
|
RpcRequest::GetStorageSlot => "getStorageSlot",
|
||||||
RpcRequest::GetStoragePubkeysForSlot => "getStoragePubkeysForSlot",
|
RpcRequest::GetStoragePubkeysForSlot => "getStoragePubkeysForSlot",
|
||||||
|
|
|
@ -6,7 +6,6 @@ use crate::contact_info::ContactInfo;
|
||||||
use crate::packet::PACKET_DATA_SIZE;
|
use crate::packet::PACKET_DATA_SIZE;
|
||||||
use crate::storage_stage::StorageState;
|
use crate::storage_stage::StorageState;
|
||||||
use bincode::{deserialize, serialize};
|
use bincode::{deserialize, serialize};
|
||||||
use bs58;
|
|
||||||
use jsonrpc_core::{Error, Metadata, Result};
|
use jsonrpc_core::{Error, Metadata, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use solana_drone::drone::request_airdrop_transaction;
|
use solana_drone::drone::request_airdrop_transaction;
|
||||||
|
@ -16,7 +15,7 @@ use solana_sdk::fee_calculator::FeeCalculator;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::Signature;
|
use solana_sdk::signature::Signature;
|
||||||
use solana_sdk::transaction::{self, Transaction};
|
use solana_sdk::transaction::{self, Transaction};
|
||||||
use std::mem;
|
use solana_vote_api::vote_state::VoteState;
|
||||||
use std::net::{SocketAddr, UdpSocket};
|
use std::net::{SocketAddr, UdpSocket};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
@ -76,9 +75,8 @@ impl JsonRpcRequestProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_recent_blockhash(&self) -> (String, FeeCalculator) {
|
fn get_recent_blockhash(&self) -> (String, FeeCalculator) {
|
||||||
let id = self.bank().confirmed_last_blockhash();
|
|
||||||
(
|
(
|
||||||
bs58::encode(id).into_string(),
|
self.bank().confirmed_last_blockhash().to_string(),
|
||||||
self.bank().fee_calculator.clone(),
|
self.bank().fee_calculator.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -104,14 +102,22 @@ impl JsonRpcRequestProcessor {
|
||||||
Ok(self.bank().transaction_count() as u64)
|
Ok(self.bank().transaction_count() as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_epoch_vote_accounts(&self) -> Result<Vec<(Pubkey, u64, VoteState)>> {
|
||||||
|
let bank = self.bank();
|
||||||
|
Ok(bank
|
||||||
|
.epoch_vote_accounts(bank.get_stakers_epoch(bank.slot()))
|
||||||
|
.ok_or_else(Error::invalid_request)?
|
||||||
|
.iter()
|
||||||
|
.map(|(k, (s, a))| (*k, *s, VoteState::from(a).unwrap_or_default()))
|
||||||
|
.collect::<Vec<_>>())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_storage_blockhash(&self) -> Result<String> {
|
fn get_storage_blockhash(&self) -> Result<String> {
|
||||||
let hash = self.storage_state.get_storage_blockhash();
|
Ok(self.storage_state.get_storage_blockhash().to_string())
|
||||||
Ok(bs58::encode(hash).into_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_storage_slot(&self) -> Result<u64> {
|
fn get_storage_slot(&self) -> Result<u64> {
|
||||||
let slot = self.storage_state.get_slot();
|
Ok(self.storage_state.get_slot())
|
||||||
Ok(slot)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_storage_pubkeys_for_slot(&self, slot: u64) -> Result<Vec<Pubkey>> {
|
fn get_storage_pubkeys_for_slot(&self, slot: u64) -> Result<Vec<Pubkey>> {
|
||||||
|
@ -136,35 +142,11 @@ fn get_tpu_addr(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<SocketAddr> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_pubkey(input: String) -> Result<Pubkey> {
|
fn verify_pubkey(input: String) -> Result<Pubkey> {
|
||||||
let pubkey_vec = bs58::decode(input).into_vec().map_err(|err| {
|
input.parse().map_err(|_e| Error::invalid_request())
|
||||||
info!("verify_pubkey: invalid input: {:?}", err);
|
|
||||||
Error::invalid_request()
|
|
||||||
})?;
|
|
||||||
if pubkey_vec.len() != mem::size_of::<Pubkey>() {
|
|
||||||
info!(
|
|
||||||
"verify_pubkey: invalid pubkey_vec length: {}",
|
|
||||||
pubkey_vec.len()
|
|
||||||
);
|
|
||||||
Err(Error::invalid_request())
|
|
||||||
} else {
|
|
||||||
Ok(Pubkey::new(&pubkey_vec))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_signature(input: &str) -> Result<Signature> {
|
fn verify_signature(input: &str) -> Result<Signature> {
|
||||||
let signature_vec = bs58::decode(input).into_vec().map_err(|err| {
|
input.parse().map_err(|_e| Error::invalid_request())
|
||||||
info!("verify_signature: invalid input: {}: {:?}", input, err);
|
|
||||||
Error::invalid_request()
|
|
||||||
})?;
|
|
||||||
if signature_vec.len() != mem::size_of::<Signature>() {
|
|
||||||
info!(
|
|
||||||
"verify_signature: invalid signature_vec length: {}",
|
|
||||||
signature_vec.len()
|
|
||||||
);
|
|
||||||
Err(Error::invalid_request())
|
|
||||||
} else {
|
|
||||||
Ok(Signature::new(&signature_vec))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -224,6 +206,9 @@ pub trait RpcSol {
|
||||||
#[rpc(meta, name = "getSlotLeader")]
|
#[rpc(meta, name = "getSlotLeader")]
|
||||||
fn get_slot_leader(&self, _: Self::Metadata) -> Result<String>;
|
fn get_slot_leader(&self, _: Self::Metadata) -> Result<String>;
|
||||||
|
|
||||||
|
#[rpc(meta, name = "getEpochVoteAccounts")]
|
||||||
|
fn get_epoch_vote_accounts(&self, _: Self::Metadata) -> Result<Vec<(Pubkey, u64, VoteState)>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getStorageBlockhash")]
|
#[rpc(meta, name = "getStorageBlockhash")]
|
||||||
fn get_storage_blockhash(&self, _: Self::Metadata) -> Result<String>;
|
fn get_storage_blockhash(&self, _: Self::Metadata) -> Result<String>;
|
||||||
|
|
||||||
|
@ -406,7 +391,7 @@ impl RpcSol for RpcSolImpl {
|
||||||
|
|
||||||
if signature_status == Some(Ok(())) {
|
if signature_status == Some(Ok(())) {
|
||||||
info!("airdrop signature ok");
|
info!("airdrop signature ok");
|
||||||
return Ok(bs58::encode(signature).into_string());
|
return Ok(signature.to_string());
|
||||||
} else if now.elapsed().as_secs() > 5 {
|
} else if now.elapsed().as_secs() > 5 {
|
||||||
info!("airdrop signature timeout");
|
info!("airdrop signature timeout");
|
||||||
return Err(Error::internal_error());
|
return Err(Error::internal_error());
|
||||||
|
@ -437,7 +422,7 @@ impl RpcSol for RpcSolImpl {
|
||||||
info!("send_transaction: send_to error: {:?}", err);
|
info!("send_transaction: send_to error: {:?}", err);
|
||||||
Error::internal_error()
|
Error::internal_error()
|
||||||
})?;
|
})?;
|
||||||
let signature = bs58::encode(tx.signatures[0]).into_string();
|
let signature = tx.signatures[0].to_string();
|
||||||
trace!(
|
trace!(
|
||||||
"send_transaction: sent {} bytes, signature={}",
|
"send_transaction: sent {} bytes, signature={}",
|
||||||
data.len(),
|
data.len(),
|
||||||
|
@ -455,6 +440,16 @@ impl RpcSol for RpcSolImpl {
|
||||||
.to_string())
|
.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_epoch_vote_accounts(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
) -> Result<Vec<(Pubkey, u64, VoteState)>> {
|
||||||
|
meta.request_processor
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get_epoch_vote_accounts()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_storage_blockhash(&self, meta: Self::Metadata) -> Result<String> {
|
fn get_storage_blockhash(&self, meta: Self::Metadata) -> Result<String> {
|
||||||
meta.request_processor
|
meta.request_processor
|
||||||
.read()
|
.read()
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
||||||
|
|
||||||
use crate::rpc_subscriptions::{Confirmations, RpcSubscriptions};
|
use crate::rpc_subscriptions::{Confirmations, RpcSubscriptions};
|
||||||
use bs58;
|
|
||||||
use jsonrpc_core::{Error, ErrorCode, Result};
|
use jsonrpc_core::{Error, ErrorCode, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use jsonrpc_pubsub::typed::Subscriber;
|
use jsonrpc_pubsub::typed::Subscriber;
|
||||||
|
@ -10,7 +9,6 @@ use solana_sdk::account::Account;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::Signature;
|
use solana_sdk::signature::Signature;
|
||||||
use solana_sdk::transaction;
|
use solana_sdk::transaction;
|
||||||
use std::mem;
|
|
||||||
use std::sync::{atomic, Arc};
|
use std::sync::{atomic, Arc};
|
||||||
|
|
||||||
#[rpc(server)]
|
#[rpc(server)]
|
||||||
|
@ -100,6 +98,16 @@ impl RpcSolPubSubImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
fn param<T: FromStr>(param_str: &str, thing: &str) -> Result<T> {
|
||||||
|
param_str.parse::<T>().map_err(|_e| Error {
|
||||||
|
code: ErrorCode::InvalidParams,
|
||||||
|
message: format!("Invalid Request: Invalid {} provided", thing),
|
||||||
|
data: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl RpcSolPubSub for RpcSolPubSubImpl {
|
impl RpcSolPubSub for RpcSolPubSubImpl {
|
||||||
type Metadata = Arc<Session>;
|
type Metadata = Arc<Session>;
|
||||||
|
|
||||||
|
@ -110,26 +118,18 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
||||||
pubkey_str: String,
|
pubkey_str: String,
|
||||||
confirmations: Option<Confirmations>,
|
confirmations: Option<Confirmations>,
|
||||||
) {
|
) {
|
||||||
let pubkey_vec = bs58::decode(pubkey_str).into_vec().unwrap();
|
match param::<Pubkey>(&pubkey_str, "pubkey") {
|
||||||
if pubkey_vec.len() != mem::size_of::<Pubkey>() {
|
Ok(pubkey) => {
|
||||||
subscriber
|
let id = self.uid.fetch_add(1, atomic::Ordering::SeqCst);
|
||||||
.reject(Error {
|
let sub_id = SubscriptionId::Number(id as u64);
|
||||||
code: ErrorCode::InvalidParams,
|
info!("account_subscribe: account={:?} id={:?}", pubkey, sub_id);
|
||||||
message: "Invalid Request: Invalid pubkey provided".into(),
|
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
||||||
data: None,
|
|
||||||
})
|
self.subscriptions
|
||||||
.unwrap();
|
.add_account_subscription(&pubkey, confirmations, &sub_id, &sink)
|
||||||
return;
|
}
|
||||||
|
Err(e) => subscriber.reject(e).unwrap(),
|
||||||
}
|
}
|
||||||
let pubkey = Pubkey::new(&pubkey_vec);
|
|
||||||
|
|
||||||
let id = self.uid.fetch_add(1, atomic::Ordering::SeqCst);
|
|
||||||
let sub_id = SubscriptionId::Number(id as u64);
|
|
||||||
info!("account_subscribe: account={:?} id={:?}", pubkey, sub_id);
|
|
||||||
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
|
||||||
|
|
||||||
self.subscriptions
|
|
||||||
.add_account_subscription(&pubkey, confirmations, &sub_id, &sink)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn account_unsubscribe(
|
fn account_unsubscribe(
|
||||||
|
@ -156,26 +156,18 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
||||||
pubkey_str: String,
|
pubkey_str: String,
|
||||||
confirmations: Option<Confirmations>,
|
confirmations: Option<Confirmations>,
|
||||||
) {
|
) {
|
||||||
let pubkey_vec = bs58::decode(pubkey_str).into_vec().unwrap();
|
match param::<Pubkey>(&pubkey_str, "pubkey") {
|
||||||
if pubkey_vec.len() != mem::size_of::<Pubkey>() {
|
Ok(pubkey) => {
|
||||||
subscriber
|
let id = self.uid.fetch_add(1, atomic::Ordering::SeqCst);
|
||||||
.reject(Error {
|
let sub_id = SubscriptionId::Number(id as u64);
|
||||||
code: ErrorCode::InvalidParams,
|
info!("program_subscribe: account={:?} id={:?}", pubkey, sub_id);
|
||||||
message: "Invalid Request: Invalid pubkey provided".into(),
|
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
||||||
data: None,
|
|
||||||
})
|
self.subscriptions
|
||||||
.unwrap();
|
.add_program_subscription(&pubkey, confirmations, &sub_id, &sink)
|
||||||
return;
|
}
|
||||||
|
Err(e) => subscriber.reject(e).unwrap(),
|
||||||
}
|
}
|
||||||
let pubkey = Pubkey::new(&pubkey_vec);
|
|
||||||
|
|
||||||
let id = self.uid.fetch_add(1, atomic::Ordering::SeqCst);
|
|
||||||
let sub_id = SubscriptionId::Number(id as u64);
|
|
||||||
info!("program_subscribe: account={:?} id={:?}", pubkey, sub_id);
|
|
||||||
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
|
||||||
|
|
||||||
self.subscriptions
|
|
||||||
.add_program_subscription(&pubkey, confirmations, &sub_id, &sink)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_unsubscribe(
|
fn program_unsubscribe(
|
||||||
|
@ -203,29 +195,25 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
||||||
confirmations: Option<Confirmations>,
|
confirmations: Option<Confirmations>,
|
||||||
) {
|
) {
|
||||||
info!("signature_subscribe");
|
info!("signature_subscribe");
|
||||||
let signature_vec = bs58::decode(signature_str).into_vec().unwrap();
|
match param::<Signature>(&signature_str, "signature") {
|
||||||
if signature_vec.len() != mem::size_of::<Signature>() {
|
Ok(signature) => {
|
||||||
subscriber
|
let id = self.uid.fetch_add(1, atomic::Ordering::SeqCst);
|
||||||
.reject(Error {
|
let sub_id = SubscriptionId::Number(id as u64);
|
||||||
code: ErrorCode::InvalidParams,
|
info!(
|
||||||
message: "Invalid Request: Invalid signature provided".into(),
|
"signature_subscribe: signature={:?} id={:?}",
|
||||||
data: None,
|
signature, sub_id
|
||||||
})
|
);
|
||||||
.unwrap();
|
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
||||||
return;
|
|
||||||
|
self.subscriptions.add_signature_subscription(
|
||||||
|
&signature,
|
||||||
|
confirmations,
|
||||||
|
&sub_id,
|
||||||
|
&sink,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(e) => subscriber.reject(e).unwrap(),
|
||||||
}
|
}
|
||||||
let signature = Signature::new(&signature_vec);
|
|
||||||
|
|
||||||
let id = self.uid.fetch_add(1, atomic::Ordering::SeqCst);
|
|
||||||
let sub_id = SubscriptionId::Number(id as u64);
|
|
||||||
info!(
|
|
||||||
"signature_subscribe: signature={:?} id={:?}",
|
|
||||||
signature, sub_id
|
|
||||||
);
|
|
||||||
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
|
||||||
|
|
||||||
self.subscriptions
|
|
||||||
.add_signature_subscription(&signature, confirmations, &sub_id, &sink);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature_unsubscribe(
|
fn signature_unsubscribe(
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
||||||
|
|
||||||
use crate::bank_forks::BankForks;
|
use crate::bank_forks::BankForks;
|
||||||
use bs58;
|
|
||||||
use core::hash::Hash;
|
use core::hash::Hash;
|
||||||
use jsonrpc_core::futures::Future;
|
use jsonrpc_core::futures::Future;
|
||||||
use jsonrpc_pubsub::typed::Sink;
|
use jsonrpc_pubsub::typed::Sink;
|
||||||
|
@ -144,7 +143,7 @@ where
|
||||||
|
|
||||||
fn notify_program(accounts: Vec<(Pubkey, Account)>, sink: &Sink<(String, Account)>, _root: u64) {
|
fn notify_program(accounts: Vec<(Pubkey, Account)>, sink: &Sink<(String, Account)>, _root: u64) {
|
||||||
for (pubkey, account) in accounts.iter() {
|
for (pubkey, account) in accounts.iter() {
|
||||||
sink.notify(Ok((bs58::encode(pubkey).into_string(), account.clone())))
|
sink.notify(Ok((pubkey.to_string(), account.clone())))
|
||||||
.wait()
|
.wait()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,11 @@ impl VoteState {
|
||||||
serialized_size(&vote_state).unwrap() as usize
|
serialized_size(&vote_state).unwrap() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// utility function, used by Stakes, tests
|
||||||
|
pub fn from(account: &Account) -> Option<VoteState> {
|
||||||
|
account.state().ok()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deserialize(input: &[u8]) -> Result<Self, InstructionError> {
|
pub fn deserialize(input: &[u8]) -> Result<Self, InstructionError> {
|
||||||
deserialize(input).map_err(|_| InstructionError::InvalidAccountData)
|
deserialize(input).map_err(|_| InstructionError::InvalidAccountData)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue