Skip to content

Commit 9a4547b

Browse files
author
snorochevskiy
committed
MTG-703 Adding peer to peer consistency checks
1 parent 5142f69 commit 9a4547b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+5849
-15
lines changed

Cargo.lock

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ indicatif = "0.17"
8181

8282
# Errors, futures, helpers, tools, time, etc...
8383
# Errors
84+
anyhow = "1"
8485
thiserror = { version = "1"}
8586
# Clients
8687
arweave-rs = { version = "0.2.0", git = "https://github.com/RequescoS/arweave-rs.git", rev = "d8f5ef76f06c96afdf013fe5b62301790631b33f" }

entities/src/models.rs

+29
Original file line numberDiff line numberDiff line change
@@ -519,19 +519,22 @@ pub struct MetadataInfo {
519519
pub rent_epoch: u64,
520520
pub executable: bool,
521521
pub metadata_owner: Option<String>,
522+
pub data_hash: u64,
522523
}
523524

524525
#[derive(Clone)]
525526
pub struct EditionMetadata {
526527
pub edition: TokenMetadataEdition,
527528
pub write_version: u64,
528529
pub slot_updated: u64,
530+
pub data_hash: u64,
529531
}
530532

531533
#[derive(Clone, Debug)]
532534
pub struct BurntMetadataSlot {
533535
pub slot_updated: u64,
534536
pub write_version: u64,
537+
pub data_hash: u64,
535538
}
536539

537540
#[derive(Clone)]
@@ -542,6 +545,7 @@ pub struct IndexableAssetWithAccountInfo {
542545
pub slot_updated: u64,
543546
pub write_version: u64,
544547
pub rent_epoch: u64,
548+
pub data_hash: u64,
545549
}
546550

547551
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -556,6 +560,7 @@ pub struct TokenAccount {
556560
pub slot_updated: i64,
557561
pub amount: i64,
558562
pub write_version: u64,
563+
pub data_hash: u64,
559564
}
560565

561566
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -569,19 +574,22 @@ pub struct Mint {
569574
pub token_program: Pubkey,
570575
pub extensions: Option<MintAccountExtensions>,
571576
pub write_version: u64,
577+
pub data_hash: u64,
572578
}
573579

574580
pub struct InscriptionInfo {
575581
pub inscription: Inscription,
576582
pub write_version: u64,
577583
pub slot_updated: u64,
584+
pub data_hash: u64,
578585
}
579586

580587
#[derive(Clone)]
581588
pub struct InscriptionDataInfo {
582589
pub inscription_data: Vec<u8>,
583590
pub write_version: u64,
584591
pub slot_updated: u64,
592+
pub data_hash: u64,
585593
}
586594

587595
#[derive(Clone)]
@@ -592,6 +600,7 @@ pub struct CoreAssetFee {
592600
pub rent_epoch: u64,
593601
pub slot_updated: u64,
594602
pub write_version: u64,
603+
pub data_hash: u64,
595604
}
596605

597606
pub struct UnprocessedAccountMessage {
@@ -600,6 +609,26 @@ pub struct UnprocessedAccountMessage {
600609
pub id: String,
601610
}
602611

612+
impl UnprocessedAccountMessage {
613+
pub fn solana_change_info(&self) -> (Pubkey, u64, u64, u64) {
614+
let (slot, write_version, data_hash) = match &self.account {
615+
UnprocessedAccount::MetadataInfo(v) => (v.slot_updated, v.write_version, v.data_hash),
616+
UnprocessedAccount::Token(v) => (v.slot_updated as u64, v.write_version, v.data_hash),
617+
UnprocessedAccount::Mint(v) => (v.slot_updated as u64, v.write_version, v.data_hash),
618+
UnprocessedAccount::Edition(v) => (v.slot_updated, v.write_version, v.data_hash),
619+
UnprocessedAccount::BurnMetadata(v) => (v.slot_updated, v.write_version, v.data_hash),
620+
UnprocessedAccount::BurnMplCore(v) => (v.slot_updated, v.write_version, v.data_hash),
621+
UnprocessedAccount::MplCore(v) => (v.slot_updated, v.write_version, v.data_hash),
622+
UnprocessedAccount::Inscription(v) => (v.slot_updated, v.write_version, v.data_hash),
623+
UnprocessedAccount::InscriptionData(v) => {
624+
(v.slot_updated, v.write_version, v.data_hash)
625+
}
626+
UnprocessedAccount::MplCoreFee(v) => (v.slot_updated, v.write_version, v.data_hash),
627+
};
628+
(self.key, slot, write_version, data_hash)
629+
}
630+
}
631+
603632
pub struct BufferedTxWithID {
604633
pub tx: BufferedTransaction,
605634
pub id: String,

grpc/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9+
anyhow = { workspace = true }
910
tokio = { workspace = true }
1011
tonic = { workspace = true }
1112
prost = { workspace = true }
1213
futures = { workspace = true }
1314
solana-sdk = { workspace = true }
1415
interface = { path = "../interface" }
1516
entities = { path = "../entities" }
17+
metrics-utils = { path = "../metrics_utils" }
1618
async-trait = { workspace = true }
1719
thiserror = { workspace = true }
1820
solana-transaction-status = { workspace = true }

grpc/build.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
fn main() -> Result<(), Box<dyn std::error::Error>> {
22
tonic_build::configure()
3+
.protoc_arg("--experimental_allow_proto3_optional")
34
.out_dir("src") // Output directory for the generated Rust code within grpc module
45
.compile(
56
&[
67
// Paths to the .proto files
78
"proto/gap_filler.proto",
89
"proto/asset_urls.proto",
10+
"proto/consistency_api.proto",
911
],
1012
&["proto"], // Include paths for proto file dependencies
1113
)?;

grpc/proto/consistency_api.proto

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
syntax = "proto3";
2+
3+
import "google/protobuf/empty.proto";
4+
5+
package consistencyapi;
6+
7+
message BbgmEarlistGrandEpoch {
8+
optional uint32 grand_epoch = 1;
9+
}
10+
11+
message BbgmGrandEpochList {
12+
repeated BbgmGrandEpoch list = 1;
13+
}
14+
15+
message BbgmGrandEpoch {
16+
uint32 grand_epoch = 1;
17+
bytes tree_pubkey = 2;
18+
optional bytes checksum = 3;
19+
}
20+
21+
message BbgmEpochList {
22+
repeated BbgmEpoch list = 1;
23+
}
24+
25+
message BbgmEpoch {
26+
uint32 epoch = 1;
27+
bytes tree_pubkey = 2;
28+
optional bytes checksum = 3;
29+
}
30+
31+
message BbgmChangeList {
32+
repeated BbgmChange list = 1;
33+
}
34+
35+
message BbgmChange {
36+
bytes tree_pubkey = 1;
37+
uint64 slot = 2;
38+
uint64 seq = 3;
39+
string signature = 4;
40+
}
41+
42+
// Request object for getting grand epoch trees checksums
43+
message GetBbgmGrandEpochsReq {
44+
// Grand epoch number
45+
uint32 grand_epoch = 1;
46+
// Maximum amount of tree checksums to return
47+
optional uint64 limit = 2;
48+
// Return trees checksums that are after given
49+
optional bytes after = 3;
50+
}
51+
52+
// Request object for getting epoch tree checksums in the geven grand epoch
53+
message GetBbgmEpochsReq {
54+
// Public key of the bubblegum tree, checksum should be returned for
55+
bytes tree_pubkey = 1;
56+
// Number of grand epoch which nested epochs should be returned
57+
uint32 grand_epoch = 2;
58+
}
59+
60+
message BbgmChangePosition {
61+
uint64 slot = 1;
62+
uint64 seq = 2;
63+
}
64+
65+
// Request object for getting list of individual bubblegum tree changes
66+
// that happened in the given epoch
67+
message GetBbgmChangesReq {
68+
// Pubkey of bubblegum tree
69+
bytes tree_pubkey = 1;
70+
// Number of epoch changes are listed from
71+
uint32 epoch = 2;
72+
// Maximum amount of bubblegum changes to return
73+
optional uint64 limit = 3;
74+
// Return changes after given position
75+
optional BbgmChangePosition after = 4;
76+
}
77+
78+
// Represents account NFT grand bucket checksum.
79+
message AccGrandBucketChecksum {
80+
uint32 grand_bucket = 1;
81+
optional bytes checksum = 2;
82+
}
83+
84+
// List of account NFT grand bucket checksums.
85+
message AccGrandBucketChecksumsList {
86+
repeated AccGrandBucketChecksum list = 1;
87+
}
88+
89+
message AccBucketChecksum {
90+
uint32 bucket = 1;
91+
optional bytes checksum = 2;
92+
}
93+
94+
message AccBucketChecksumsList {
95+
repeated AccBucketChecksum list = 1;
96+
}
97+
98+
// Represents last tracked account NFT change
99+
message Acc {
100+
bytes account_pubkey = 1;
101+
uint64 slot = 2;
102+
uint64 write_version = 3;
103+
}
104+
105+
// Represents list of last tracked account NFT changes
106+
message AccList {
107+
repeated Acc list = 1;
108+
}
109+
110+
message GetAccBucketsReq {
111+
uint32 grand_bucket = 1;
112+
}
113+
114+
message GetAccReq {
115+
// number of bucket
116+
uint32 bucket = 1;
117+
// maximum amount of account latest states to return
118+
optional uint64 limit = 2;
119+
// return account that are after the given
120+
optional bytes after = 3;
121+
}
122+
123+
service BbgmConsistencyService {
124+
// Returns earliest grand epoch avaible on the peer.
125+
rpc GetBbgmEarliestGrandEpoch(google.protobuf.Empty) returns (BbgmEarlistGrandEpoch);
126+
127+
// Request list of tree checksums in the given grand epoch
128+
// No need to use stream since in the worst case the response size
129+
// is still significanly less than 1 MB
130+
rpc GetBbgmGrandEpochChecksums(GetBbgmGrandEpochsReq) returns (BbgmGrandEpochList);
131+
rpc GetBbgmEpochChecksumsInGrandEpoch(GetBbgmEpochsReq) returns (BbgmEpochList);
132+
rpc GetBbgmChangesInEpoch(GetBbgmChangesReq) returns (BbgmChangeList);
133+
134+
// Propose bubblegum changes to a peer, that has these changes missing.
135+
// Can be called after after the "get changes" API is called, and a portion
136+
// of missing bubblegum changes detected on the peer.
137+
rpc ProposeMissingBbgmChanges(BbgmChangeList) returns (google.protobuf.Empty);
138+
}
139+
140+
service AccConsistencyService {
141+
rpc GetAccGrandBucketChecksums(google.protobuf.Empty) returns (AccGrandBucketChecksumsList);
142+
rpc GetAccBucketChecksumsInGrandBucket(GetAccBucketsReq) returns (AccBucketChecksumsList);
143+
rpc GetAccsInBucket(GetAccReq) returns (AccList);
144+
145+
rpc ProposeMissingAccChanges(AccList) returns (google.protobuf.Empty);
146+
}

grpc/src/client.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ pub struct Client {
2121

2222
impl Client {
2323
pub async fn connect(peer_discovery: impl PeerDiscovery) -> Result<Self, GrpcError> {
24-
let url = Uri::from_str(peer_discovery.get_gapfiller_peer_addr().as_str())
25-
.map_err(|e| GrpcError::UriCreate(e.to_string()))?;
24+
Client::connect_to_url(peer_discovery.get_gapfiller_peer_addr().as_str()).await
25+
}
26+
27+
pub async fn connect_to_url(url_str: &str) -> Result<Self, GrpcError> {
28+
let url = Uri::from_str(url_str).map_err(|e| GrpcError::UriCreate(e.to_string()))?;
2629
let channel = Channel::builder(url).connect().await?;
2730

2831
Ok(Self {

0 commit comments

Comments
 (0)