Receive
This commit is contained in:
parent
a54ac76523
commit
2bab960f23
9 changed files with 62500 additions and 911 deletions
51
g1bridge/src/indexer.rs
Normal file
51
g1bridge/src/indexer.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
/*
|
||||
[
|
||||
{
|
||||
"data": {
|
||||
"transfer": [
|
||||
{
|
||||
"amount": 42,
|
||||
"comment": null
|
||||
},
|
||||
{
|
||||
"amount": 30,
|
||||
"comment": {"remark": "tuxmain"}
|
||||
}
|
||||
],
|
||||
"block": [
|
||||
{
|
||||
"height": 7040132,
|
||||
"hash": "\\xe669ff0d26dc9c48ec905916d39b0f11447cf63a37c0d1094f19cdfbbb199c67"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
*/
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Comment {
|
||||
pub remark: String,
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Transfer {
|
||||
pub amount: u64,
|
||||
pub comment: Option<Comment>,
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Block {
|
||||
pub height: u64,
|
||||
pub hash: String,
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Data {
|
||||
pub transfer: Vec<Transfer>,
|
||||
pub block: Vec<Block>,
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DataWrapper {
|
||||
pub data: Data,
|
||||
}
|
||||
pub type Response = Vec<DataWrapper>;
|
||||
|
|
@ -1,22 +1,23 @@
|
|||
#![feature(try_blocks)]
|
||||
|
||||
mod blockchain;
|
||||
mod indexer;
|
||||
mod response;
|
||||
|
||||
use argp::FromArgs;
|
||||
use serde::{Deserialize, Serialize, de};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sp_core::Pair as _;
|
||||
use std::{
|
||||
io::{BufRead, Read},
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
collections::{hash_map::Entry, HashMap}, io::{BufRead, Read}, str::FromStr, sync::Arc
|
||||
};
|
||||
use subxt::{
|
||||
ext::sp_core::ed25519::{Pair, Public},
|
||||
utils::{AccountId32, MultiAddress},
|
||||
ext::sp_core::ed25519::Pair,
|
||||
utils::AccountId32,
|
||||
};
|
||||
use tiny_http::{Response, ResponseBox, Server, ServerConfig};
|
||||
use tiny_http::{Response, ResponseBox, Server};
|
||||
use tokio::sync::mpsc::{Sender, channel};
|
||||
use typed_sled::Tree;
|
||||
use log::error;
|
||||
|
||||
/// Game to Blockchain
|
||||
const TREE_DEBT_G2B: &'static str = "debt_g2b";
|
||||
|
|
@ -28,6 +29,10 @@ struct Opt {
|
|||
#[argp(option, short = 'd')]
|
||||
db: String,
|
||||
|
||||
/// Duniter indexer URL
|
||||
#[argp(option, short = 'i', default = "String::from(\"https://squid.gdev.gyroi.de/v1/graphql\")")]
|
||||
indexer: String,
|
||||
|
||||
/// secret key is legacy (two passwords on the two first lines)
|
||||
#[argp(switch, short = 'l')]
|
||||
legacy: bool,
|
||||
|
|
@ -80,12 +85,16 @@ async fn main() {
|
|||
.expect("Cannot read secret key file");
|
||||
Pair::from_string(sk_content.trim(), None).expect("Cannot decode secret key")
|
||||
};
|
||||
let pk: AccountId32 = pair.public().into();
|
||||
let pk_str = pk.to_string();
|
||||
|
||||
simplelog::SimpleLogger::init(log::LevelFilter::Debug, simplelog::Config::default()).unwrap();
|
||||
|
||||
let db = typed_sled::open(opt.db).expect("Cannot open database");
|
||||
let tree_debt_g2b = Tree::<DebtG2B, ()>::open(&db, TREE_DEBT_G2B);
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let (bc_send, bc_recv) = channel(128);
|
||||
|
||||
tokio::spawn(blockchain::run(
|
||||
|
|
@ -100,6 +109,8 @@ async fn main() {
|
|||
struct Locals {
|
||||
tree_debt_g2b: Tree<DebtG2B, ()>,
|
||||
bc_send: Sender<DebtG2B>,
|
||||
indexer: String,
|
||||
pk_str: String,
|
||||
}
|
||||
|
||||
tokio::task_local! {
|
||||
|
|
@ -110,10 +121,13 @@ async fn main() {
|
|||
Arc::new(Locals {
|
||||
tree_debt_g2b,
|
||||
bc_send,
|
||||
indexer: opt.indexer,
|
||||
pk_str: pk_str,
|
||||
}),
|
||||
async move {
|
||||
for request in server.incoming_requests() {
|
||||
let locals = LOCALS.get();
|
||||
let client = client.clone();
|
||||
tokio::spawn(async move {
|
||||
let url = request.url();
|
||||
|
||||
|
|
@ -124,7 +138,6 @@ async fn main() {
|
|||
Some("send") => {
|
||||
let address = AccountId32::from_str(url_items.next()?).ok()?;
|
||||
let amount = url_items.next()?.parse::<u64>().ok()?;
|
||||
println!("{address} {amount}");
|
||||
|
||||
let debt = DebtG2B { address, amount };
|
||||
locals.tree_debt_g2b.insert(&debt, &()).ok()?;
|
||||
|
|
@ -132,6 +145,52 @@ async fn main() {
|
|||
|
||||
Response::empty(200).boxed()
|
||||
}
|
||||
Some("recv") => {
|
||||
let block_number = url_items.next()?.parse::<u64>().ok()?;
|
||||
let req = client.post(&locals.indexer).body(dbg!(format!(
|
||||
r#"[{{"query":"{{transfer(where:{{blockNumber:{{_gt:{}}},to:{{id:{{_eq:\"{}\"}}}}}}){{amount comment{{remark}}}}block(limit:1,orderBy:{{height:DESC}}){{height hash}}}}"}}]"#,
|
||||
block_number, locals.pk_str))).build().unwrap();
|
||||
let Ok(res) = client.execute(req).await else {
|
||||
request.respond(Response::empty(500)).ok();
|
||||
error!("Error from indexer");
|
||||
return;
|
||||
};
|
||||
let Ok(res) = res.json::<indexer::Response>().await else {
|
||||
request.respond(Response::empty(500)).ok();
|
||||
error!("Bad JSON from indexer");
|
||||
return;
|
||||
};
|
||||
let Some(data) = res.first() else {
|
||||
request.respond(Response::empty(500)).ok();
|
||||
error!("No data from indexer");
|
||||
return;
|
||||
};
|
||||
let Some(block) = data.data.block.first() else {
|
||||
request.respond(Response::empty(500)).ok();
|
||||
error!("No block from indexer");
|
||||
return;
|
||||
};
|
||||
let mut debts = HashMap::<String, u64>::new();
|
||||
for transfer in data.data.transfer.iter() {
|
||||
if let Some(comment) = &transfer.comment {
|
||||
match debts.entry(comment.remark.clone()) {
|
||||
Entry::Occupied(mut debt) => {
|
||||
*debt.get_mut() = debt.get().saturating_add(transfer.amount);
|
||||
}
|
||||
Entry::Vacant(debt) => {
|
||||
debt.insert(transfer.amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Response::from_string(serde_json::to_string(&response::Response {
|
||||
block: block.height,
|
||||
debts: debts.into_iter().map(|(name, amount)| response::Debt {
|
||||
name,
|
||||
amount,
|
||||
}).collect(),
|
||||
}).unwrap()).with_status_code(200).boxed()
|
||||
}
|
||||
_ => None?,
|
||||
}
|
||||
};
|
||||
|
|
|
|||
13
g1bridge/src/response.rs
Normal file
13
g1bridge/src/response.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Debt {
|
||||
pub name: String,
|
||||
pub amount: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Response {
|
||||
pub block: u64,
|
||||
pub debts: Vec<Debt>,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue