Skip to content

Commit 055b32c

Browse files
committed
nostr sign / verify cleanup
1 parent f243ad0 commit 055b32c

File tree

5 files changed

+151
-199
lines changed

5 files changed

+151
-199
lines changed

client/src/bin/space-cli.rs

Lines changed: 29 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ use spaces_client::{
3737
};
3838
use spaces_protocol::bitcoin::{Amount, FeeRate, OutPoint, Txid};
3939
use spaces_wallet::{
40-
bitcoin::secp256k1::schnorr::Signature,
41-
export::WalletExport,
42-
nostr::{NostrEvent, NostrTag},
43-
Listing,
40+
bitcoin::secp256k1::schnorr::Signature, export::WalletExport, nostr::NostrEvent, Listing,
4441
};
4542

4643
#[derive(Parser, Debug)]
@@ -268,10 +265,6 @@ enum Commands {
268265
/// Path to a Nostr event json file (omit for stdin)
269266
#[arg(short, long)]
270267
input: Option<PathBuf>,
271-
272-
/// Include a space-tag and trust path data
273-
#[arg(short, long)]
274-
anchor: bool,
275268
},
276269
/// Verify a signed Nostr event against the space's public key
277270
#[command(name = "verifyevent")]
@@ -290,9 +283,6 @@ enum Commands {
290283
space: String,
291284
/// The DNS zone file path (omit for stdin)
292285
input: Option<PathBuf>,
293-
/// Skip including bundled Merkle proof in the event.
294-
#[arg(long)]
295-
skip_anchor: bool,
296286
},
297287
/// Updates the Merkle trust path for space-anchored Nostr events
298288
#[command(name = "refreshanchor")]
@@ -439,62 +429,15 @@ impl SpaceCli {
439429
&self,
440430
space: String,
441431
event: NostrEvent,
442-
anchor: bool,
443432
most_recent: bool,
444433
) -> Result<NostrEvent, ClientError> {
445-
let mut result = self
434+
let result = self
446435
.client
447-
.wallet_sign_event(&self.wallet, &space, event)
436+
.wallet_sign_event(&self.wallet, &space, event, Some(most_recent))
448437
.await?;
449438

450-
if anchor {
451-
result = self.add_anchor(result, most_recent).await?
452-
}
453-
454439
Ok(result)
455440
}
456-
async fn add_anchor(
457-
&self,
458-
mut event: NostrEvent,
459-
most_recent: bool,
460-
) -> Result<NostrEvent, ClientError> {
461-
let space = match event.space() {
462-
None => {
463-
return Err(ClientError::Custom(
464-
"A space tag is required to add an anchor".to_string(),
465-
))
466-
}
467-
Some(space) => space,
468-
};
469-
470-
let spaceout = self
471-
.client
472-
.get_space(&space)
473-
.await
474-
.map_err(|e| ClientError::Custom(e.to_string()))?
475-
.ok_or(ClientError::Custom(format!(
476-
"Space not found \"{}\"",
477-
space
478-
)))?;
479-
480-
event.proof = Some(
481-
base64::prelude::BASE64_STANDARD.encode(
482-
self.client
483-
.prove_spaceout(
484-
OutPoint {
485-
txid: spaceout.txid,
486-
vout: spaceout.spaceout.n as _,
487-
},
488-
Some(most_recent),
489-
)
490-
.await
491-
.map_err(|e| ClientError::Custom(e.to_string()))?
492-
.proof,
493-
),
494-
);
495-
496-
Ok(event)
497-
}
498441
async fn send_request(
499442
&self,
500443
req: Option<RpcWalletRequest>,
@@ -893,42 +836,20 @@ async fn handle_commands(cli: &SpaceCli, command: Commands) -> Result<(), Client
893836
cli.client.verify_listing(listing).await?;
894837
println!("{} Listing verified", "✓".color(Color::Green));
895838
}
896-
Commands::SignEvent {
897-
mut space,
898-
input,
899-
anchor,
900-
} => {
901-
let mut event = read_event(input)
839+
Commands::SignEvent { space, input } => {
840+
let space = normalize_space(&space);
841+
let event = read_event(input)
902842
.map_err(|e| ClientError::Custom(format!("input error: {}", e.to_string())))?;
903843

904-
space = normalize_space(&space);
905-
match event.space() {
906-
None if anchor => event
907-
.tags
908-
.insert(0, NostrTag(vec!["space".to_string(), space.clone()])),
909-
Some(tag) => {
910-
if tag != space {
911-
return Err(ClientError::Custom(format!(
912-
"Expected a space tag with value '{}', got '{}'",
913-
space, tag
914-
)));
915-
}
916-
}
917-
_ => {}
918-
};
919-
920-
let result = cli.sign_event(space, event, anchor, false).await?;
844+
let result = cli.sign_event(space, event, false).await?;
921845
println!("{}", serde_json::to_string(&result).expect("result"));
922846
}
923-
Commands::SignZone {
924-
space,
925-
input,
926-
skip_anchor,
927-
} => {
928-
let update = encode_dns_update(&space, input)
847+
Commands::SignZone { space, input } => {
848+
let space = normalize_space(&space);
849+
let event = encode_dns_update(input)
929850
.map_err(|e| ClientError::Custom(format!("Parse error: {}", e)))?;
930-
let result = cli.sign_event(space, update, !skip_anchor, false).await?;
931851

852+
let result = cli.sign_event(space, event, false).await?;
932853
println!("{}", serde_json::to_string(&result).expect("result"));
933854
}
934855
Commands::RefreshAnchor {
@@ -937,34 +858,31 @@ async fn handle_commands(cli: &SpaceCli, command: Commands) -> Result<(), Client
937858
} => {
938859
let event = read_event(input)
939860
.map_err(|e| ClientError::Custom(format!("input error: {}", e.to_string())))?;
940-
let space = match event.space() {
941-
None => {
942-
return Err(ClientError::Custom(
943-
"Not a space-anchored event (no space tag)".to_string(),
944-
))
945-
}
946-
Some(space) => space,
947-
};
948-
949-
let mut event = cli
950-
.client
951-
.verify_event(&space, event)
861+
cli.client
862+
.verify_event(event.clone())
952863
.await
953864
.map_err(|e| ClientError::Custom(e.to_string()))?;
954-
event.proof = None;
955-
event = cli.add_anchor(event, prefer_recent).await?;
956865

957-
println!("{}", serde_json::to_string(&event).expect("result"));
866+
let e = event.clone();
867+
let space = e.get_space_tag().expect("space tag").0;
868+
let result = cli
869+
.client
870+
.wallet_sign_event(&cli.wallet, space, event, Some(prefer_recent))
871+
.await?;
872+
println!("{}", serde_json::to_string(&result).expect("result"));
958873
}
959874
Commands::VerifyEvent { space, input } => {
960875
let event = read_event(input)
961876
.map_err(|e| ClientError::Custom(format!("input error: {}", e.to_string())))?;
962-
let event = cli
963-
.client
964-
.verify_event(&space, event)
877+
cli.client
878+
.verify_event(event.clone())
965879
.await
966880
.map_err(|e| ClientError::Custom(e.to_string()))?;
967-
881+
if event.get_space_tag().expect("space tag").0 != &space {
882+
return Err(ClientError::Custom(
883+
"Space tag does not match specified space".to_string(),
884+
));
885+
}
968886
println!("{}", serde_json::to_string(&event).expect("result"));
969887
}
970888
}
@@ -976,7 +894,7 @@ fn default_rpc_url(chain: &ExtendedNetwork) -> String {
976894
format!("http://127.0.0.1:{}", default_spaces_rpc_port(chain))
977895
}
978896

979-
fn encode_dns_update(space: &str, zone_file: Option<PathBuf>) -> anyhow::Result<NostrEvent> {
897+
fn encode_dns_update(zone_file: Option<PathBuf>) -> anyhow::Result<NostrEvent> {
980898
// domain crate panics if zone doesn't end in a new line
981899
let zone = get_input(zone_file)? + "\n";
982900

@@ -1000,7 +918,7 @@ fn encode_dns_update(space: &str, zone_file: Option<PathBuf>) -> anyhow::Result<
1000918
Ok(NostrEvent::new(
1001919
871_222,
1002920
&base64::prelude::BASE64_STANDARD.encode(msg.as_slice()),
1003-
vec![NostrTag(vec!["space".to_string(), space.to_string()])],
921+
vec![],
1004922
))
1005923
}
1006924

client/src/rpc.rs

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{
44
};
55

66
use anyhow::{anyhow, Context};
7+
use base64::Engine;
78
use bdk::{
89
bitcoin::{Amount, BlockHash, FeeRate, Network, Txid},
910
chain::BlockId,
@@ -49,19 +50,18 @@ use tokio::{
4950
};
5051

5152
use crate::auth::BasicAuthLayer;
52-
use crate::wallets::WalletInfoWithProgress;
5353
use crate::{
5454
calc_progress,
5555
checker::TxChecker,
56-
client::{BlockMeta, TxEntry, BlockchainInfo},
56+
client::{BlockMeta, BlockchainInfo, TxEntry},
5757
config::ExtendedNetwork,
5858
deserialize_base64, serialize_base64,
5959
source::BitcoinRpc,
6060
spaces::{COMMIT_BLOCK_INTERVAL, ROOT_ANCHORS_COUNT},
6161
store::{ChainState, LiveSnapshot, RolloutEntry, Sha256},
6262
wallets::{
6363
AddressKind, ListSpacesResponse, RpcWallet, TxInfo, TxResponse, WalletCommand,
64-
WalletResponse,
64+
WalletInfoWithProgress, WalletResponse,
6565
},
6666
};
6767

@@ -147,9 +147,8 @@ pub enum ChainStateCommand {
147147
resp: Responder<anyhow::Result<()>>,
148148
},
149149
VerifyEvent {
150-
space: String,
151150
event: NostrEvent,
152-
resp: Responder<anyhow::Result<NostrEvent>>,
151+
resp: Responder<anyhow::Result<()>>,
153152
},
154153
ProveSpaceout {
155154
outpoint: OutPoint,
@@ -221,18 +220,15 @@ pub trait Rpc {
221220
async fn wallet_import(&self, wallet: WalletExport) -> Result<(), ErrorObjectOwned>;
222221

223222
#[method(name = "verifyevent")]
224-
async fn verify_event(
225-
&self,
226-
space: &str,
227-
event: NostrEvent,
228-
) -> Result<NostrEvent, ErrorObjectOwned>;
223+
async fn verify_event(&self, event: NostrEvent) -> Result<(), ErrorObjectOwned>;
229224

230225
#[method(name = "walletsignevent")]
231226
async fn wallet_sign_event(
232227
&self,
233228
wallet: &str,
234229
space: &str,
235230
event: NostrEvent,
231+
most_recent: Option<bool>,
236232
) -> Result<NostrEvent, ErrorObjectOwned>;
237233

238234
#[method(name = "walletgetinfo")]
@@ -507,7 +503,11 @@ impl WalletManager {
507503
Ok(export)
508504
}
509505

510-
pub async fn create_wallet(&self, client: &reqwest::Client, name: &str) -> anyhow::Result<String> {
506+
pub async fn create_wallet(
507+
&self,
508+
client: &reqwest::Client,
509+
name: &str,
510+
) -> anyhow::Result<String> {
511511
let mnemonic: GeneratedKey<_, Tap> =
512512
Mnemonic::generate((WordCount::Words12, Language::English))
513513
.map_err(|_| anyhow!("Mnemonic generation error"))?;
@@ -518,7 +518,12 @@ impl WalletManager {
518518
Ok(mnemonic.to_string())
519519
}
520520

521-
pub async fn recover_wallet(&self, client: &reqwest::Client, name: &str, mnemonic: &str) -> anyhow::Result<()> {
521+
pub async fn recover_wallet(
522+
&self,
523+
client: &reqwest::Client,
524+
name: &str,
525+
mnemonic: &str,
526+
) -> anyhow::Result<()> {
522527
let start_block = self.get_wallet_start_block(client).await?;
523528
self.setup_new_wallet(name.to_string(), mnemonic.to_string(), start_block)?;
524529
self.load_wallet(name).await?;
@@ -892,13 +897,9 @@ impl RpcServer for RpcServerImpl {
892897
})
893898
}
894899

895-
async fn verify_event(
896-
&self,
897-
space: &str,
898-
event: NostrEvent,
899-
) -> Result<NostrEvent, ErrorObjectOwned> {
900+
async fn verify_event(&self, event: NostrEvent) -> Result<(), ErrorObjectOwned> {
900901
self.store
901-
.verify_event(space, event)
902+
.verify_event(event)
902903
.await
903904
.map_err(|error| ErrorObjectOwned::owned(-1, error.to_string(), None::<String>))
904905
}
@@ -907,8 +908,27 @@ impl RpcServer for RpcServerImpl {
907908
&self,
908909
wallet: &str,
909910
space: &str,
910-
event: NostrEvent,
911+
mut event: NostrEvent,
912+
most_recent: Option<bool>,
911913
) -> Result<NostrEvent, ErrorObjectOwned> {
914+
let most_recent = most_recent.unwrap_or(false);
915+
let spaceout = self.get_space(space).await?.ok_or(ErrorObjectOwned::owned(
916+
-1,
917+
format!("Space not found \"{}\"", space),
918+
None::<String>,
919+
))?;
920+
let proof = base64::prelude::BASE64_STANDARD.encode(
921+
self.prove_spaceout(
922+
OutPoint {
923+
txid: spaceout.txid,
924+
vout: spaceout.spaceout.n as _,
925+
},
926+
Some(most_recent),
927+
)
928+
.await?
929+
.proof,
930+
);
931+
event.set_space_tag(space, &proof);
912932
self.wallet(&wallet)
913933
.await?
914934
.send_sign_event(space, event)
@@ -1281,12 +1301,8 @@ impl AsyncChainState {
12811301
SpacesWallet::verify_listing::<Sha256>(chain_state, &listing).map(|_| ()),
12821302
);
12831303
}
1284-
ChainStateCommand::VerifyEvent { space, event, resp } => {
1285-
_ = resp.send(SpacesWallet::verify_event::<Sha256>(
1286-
chain_state,
1287-
&space,
1288-
event,
1289-
));
1304+
ChainStateCommand::VerifyEvent { event, resp } => {
1305+
_ = resp.send(SpacesWallet::verify_event::<Sha256>(chain_state, event));
12901306
}
12911307
ChainStateCommand::ProveSpaceout {
12921308
prefer_recent,
@@ -1474,14 +1490,10 @@ impl AsyncChainState {
14741490
resp_rx.await?
14751491
}
14761492

1477-
pub async fn verify_event(&self, space: &str, event: NostrEvent) -> anyhow::Result<NostrEvent> {
1493+
pub async fn verify_event(&self, event: NostrEvent) -> anyhow::Result<()> {
14781494
let (resp, resp_rx) = oneshot::channel();
14791495
self.sender
1480-
.send(ChainStateCommand::VerifyEvent {
1481-
space: space.to_string(),
1482-
event,
1483-
resp,
1484-
})
1496+
.send(ChainStateCommand::VerifyEvent { event, resp })
14851497
.await?;
14861498
resp_rx.await?
14871499
}

0 commit comments

Comments
 (0)