Avatar
Lez
cfd7df62799a22e384a4ab5da8c4026c875b119d0f47c2716b20cdac9cc1f1a6
Inventor of nsite, building tribewiki.org. Biohacker.

Köszi a megosztást. Azért még messze nincs vállalható szinten, épphogy csak működik. Még profilja sincs szegény polipnak.

Replying to Avatar daniele

We already talked about something similar months ago, if I'm not wrong with nostr:npub1jlrs53pkdfjnts29kveljul2sm0actt6n8dxrrzqcersttvcuv3qdjynqn. The idea was to invite people to join Nostr and do the PoW for them using a specific kind for delegated PoW as soon as they create the account, to allow them immediate access to a PoW-restricted relay.

The difficulty adjustment and forcing a redo is an interesting option.

I think all of these ideas should be available, with the ability to combine them all. Delegated, replaceable PoW on pubkeys or event ids.

This unlocks some interesting functionalities, like being able to set a higher bar for entering a community / flagging content, the difficulty being adjusted by moderators based on the amount of resources they have. If the community sees good quality content with low PoW, they can hive-boost the PoW to raise the content to the front of moderators' eyes. Good content could stand out this way.

Higher PoW is also a nice way to kickstart an anonymous profile with no web of trust at all.

I'm annoyed by most #nip07 clients on desktop. When I visit one, it shows me the landing page, then immediately puts a popup over it, asking for my permissio

n for reading my pubkey.

How should I know if I want to grant permission or not, if I haven't even read the page? I picked gitworkshop in the screenshot, but all applications do this

because there's simply no other way to get the public key via the NIP-07 API. We need one.

I'm submitting a simple, backward-compatible change to NIP-07 to address this problem and give a chance to app developers to provide a decent user experience

on desktop w/ extension.

https://github.com/nostr-protocol/nips/pull/1599

To not loose THE game and stay free, we need Bitcoin. But Bitcoin is not enough. We need to turn our focus in one common direction: towards freedom. We must stand still against all the forces that want to divide us. Thus, we need Nostr, too. We unite on Nostr. But that's not enough. We need to grow up to the challenge. We need to develop focus, morals, consciousness, physical and mental energy, empathy, self confidence and faith in every one of us, individually. We need to be disciplined and kind while we are marching towards our common goal.

Infinite scrolling is not our friend on this path. It is there to gain the masses over from the walled gardens. We need tools for collaboration that work for us, helps us to teach each other to the good things, let us live without unneccessary compromises and NOT to distract us!

If there is no blossom sha256 for a tag, it cannot be cloned from blossom. I think it is not the expected behaviour from the user. If he makes the move from github to blossom, then removes github.com clone url from the repo announcement even, then he will be disappointed if he cannot clone old versions.

I think blossom keys should be added to each ref upon the first push to blossom to keep the functionality.

Yes, we can hardcode it, but then I guess we don't even need to handle it in ngit init nor add it to the blossom tag. Or I might misunderstand something.

The way it works in the current version of git-remote-blossom is that it saves both the sha1 and the sha256 hash in the state event. So a ref tag looks like this:

`["refs/heads/master", "3437fd950d4ba37ba51e3bc788025698cfb20ca1", "3b58e484825e5b96428ab0b0c19cb760d5ebbd39acb4795446a89c99482e2d62"],`

It needs the sha256 to be able to start the graph traversal at the HEAD. All the rest can be calculated.

This is somewhat diverges from the current NIP-34. It needs to be updated with the sha256 - which is right now in the place of the optional parent commit ids.

Passing commit ID's are fine for pushes. But for fetch, I need the blossom sha256 hashes instead of the commit IDs in order to find the blobs on blossom.

Replying to Avatar DanConwayDev

here you go nostr:npub1elta7cneng3w8p9y4dw633qzdjr4kyvaparuyuttyrx6e8xp7xnq32cume. I didn't build any dummy binaries to test it with, so don't expect it to work yet or anything.

Sure, no expectations here!

As an initial note, I think I'll need the blossom server to be passed down in args to the scripts.

#asknostr

Do you prefer "master" branch or "main" branch in git?

(master: 👍 main: 🤙)

Sorry, I googled it myself and I didn't realize it's such difficult to find.

So here it goes: https://handshake.org

The idea originated from Aaron Swartz: http://www.aaronsw.com/weblog/squarezooko

Replying to Avatar DanConwayDev

From 6bcb58925ad5a7ec2421718fb2996add9080f7bc Mon Sep 17 00:00:00 2001

From: DanConwayDev

Date: Fri, 15 Nov 2024 11:57:10 +0000

Subject: [PATCH] feat(blossom): blossom as remote using packs

This is a WIP exploration of the use of blossom as an optional

alternative to using a git server.

The incomplete code focuses on how blossom could fit with nip34

to most efficently replace the git server. It is missing the actual

blossom interaction which would hopefully would be facilited by

a new blossom feature in rust-nostr.

This implementation tries to minimise the number of blobs required

for download by using packs.

If a branch tip is at height 1304 it will split the commits in into

a number of packs. a pack the first 1024 commits, the next 256, the

next 16 and the final 8.

I planned for the identification of blossom servers to mirror the

approach taken for relays:

1. list repository blossom servers in repo announcement event

kind 30617

2. also push to user blossom servers in the standard event for that

This is not implemented, along with the rest of the blossom aspects.

I'm publishing this now as

nostr:npub1elta7cneng3w8p9y4dw633qzdjr4kyvaparuyuttyrx6e8xp7xnq32cume

has recently published a POC of an alternative approach and it makes

sense to this alternative idea.

---

Cargo.lock | 1 +

Cargo.toml | 1 +

src/bin/git_remote_nostr/fetch.rs | 4 ++++

src/bin/git_remote_nostr/list.rs | 23 ++++++++++++++++++++++-

src/bin/git_remote_nostr/push.rs | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----

src/lib/repo_state.rs | 17 ++++++++++++++++-

6 files changed, 163 insertions(+), 7 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock

index b20b60a..72b37a2 100644

--- a/Cargo.lock

+++ b/Cargo.lock

@@ -1805,6 +1805,7 @@ dependencies = [

"serde_json",

"serde_yaml",

"serial_test",

+ "sha2",

"test_utils",

"tokio",

"urlencoding",

diff --git a/Cargo.toml b/Cargo.toml

index ed99aea..320a9f0 100644

--- a/Cargo.toml

+++ b/Cargo.toml

@@ -38,6 +38,7 @@ serde_yaml = "0.9.27"

tokio = "1.33.0"

urlencoding = "2.1.3"

zeroize = "1.6.0"

+sha2 = "0.10.8"

[dev-dependencies]

assert_cmd = "2.0.12"

diff --git a/src/bin/git_remote_nostr/fetch.rs b/src/bin/git_remote_nostr/fetch.rs

index a972a2f..a1116c5 100644

--- a/src/bin/git_remote_nostr/fetch.rs

+++ b/src/bin/git_remote_nostr/fetch.rs

@@ -49,6 +49,10 @@ pub async fn run_fetch(

let term = console::Term::stderr();

for git_server_url in &repo_ref.git_server {

+ if git_server_url.eq("blossom") {

+ // TODO download missing blobs

+ continue;

+ }

let term = console::Term::stderr();

if let Err(error) = fetch_from_git_server(

git_repo,

diff --git a/src/bin/git_remote_nostr/list.rs b/src/bin/git_remote_nostr/list.rs

index 92faa6b..d71c2d1 100644

--- a/src/bin/git_remote_nostr/list.rs

+++ b/src/bin/git_remote_nostr/list.rs

@@ -43,7 +43,28 @@ pub async fn run_list(

let term = console::Term::stderr();

- let remote_states = list_from_remotes(&term, git_repo, &repo_ref.git_server, decoded_nostr_url);

+ let mut remote_states = list_from_remotes(

+ &term,

+ git_repo,

+ &repo_ref

+ .git_server

+ .iter()

+ // blossom will always match nostr state

+ .filter(|s| !s.starts_with("blossom"))

+ .map(std::borrow::ToOwned::to_owned)

+ .collect::>(),

+ decoded_nostr_url,

+ );

+ if repo_ref.git_server.iter().any(|s| s.eq("blossom")) {

+ if let Some(nostr_state) = nostr_state.clone() {

+ remote_states.insert("blossom".to_owned(), nostr_state.state.clone());

+ } else if let Some((_, state)) = remote_states.iter().last() {

+ remote_states.insert("blossom".to_owned(), state.clone());

+ } else {

+ // create blank state if no nostr state exists yet

+ remote_states.insert("blossom".to_owned(), HashMap::new());

+ }

+ }

let mut state = if let Some(nostr_state) = nostr_state {

for (name, value) in &nostr_state.state {

diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs

index db86c04..a12e8ba 100644

--- a/src/bin/git_remote_nostr/push.rs

+++ b/src/bin/git_remote_nostr/push.rs

@@ -2,6 +2,7 @@ use core::str;

use std::{

collections::{HashMap, HashSet},

io::Stdin,

+ str::FromStr,

sync::{Arc, Mutex},

time::Instant,

};

@@ -11,7 +12,7 @@ use auth_git2::GitAuthenticator;

use client::{get_events_from_cache, get_state_from_cache, send_events, sign_event, STATE_KIND};

use console::Term;

use git::{sha1_to_oid, RepoActions};

-use git2::{Oid, Repository};

+use git2::{Buf, Commit, Oid, Repository};

use git_events::{

generate_cover_letter_and_patch_events, generate_patch_event, get_commit_id_from_patch,

};

@@ -29,11 +30,17 @@ use ngit::{

};

use nostr::nips::nip10::Marker;

use nostr_sdk::{

- hashes::sha1::Hash as Sha1Hash, Event, EventBuilder, EventId, Kind, PublicKey, Tag,

+ hashes::{

+ hex::DisplayHex,

+ sha1::Hash as Sha1Hash,

+ sha256::{self, Hash as Sha256Hash},

+ },

+ Event, EventBuilder, EventId, Kind, PublicKey, Tag,

};

use nostr_signer::NostrSigner;

use repo_ref::RepoRef;

use repo_state::RepoState;

+use sha2::{Digest, Sha256};

use crate::{

client::Client,

@@ -74,7 +81,17 @@ pub async fn run_push(

let list_outputs = match list_outputs {

Some(outputs) => outputs,

- _ => list_from_remotes(&term, git_repo, &repo_ref.git_server, decoded_nostr_url),

+ _ => list_from_remotes(

+ &term,

+ git_repo,

+ &repo_ref

+ .git_server

+ .iter()

+ .filter(|s| !s.eq(&"blossom"))

+ .map(std::string::ToString::to_string)

+ .collect(),

+ decoded_nostr_url,

+ ),

};

let nostr_state = get_state_from_cache(git_repo.get_path()?, repo_ref).await;

@@ -150,11 +167,24 @@ pub async fn run_push(

}

}

+ let mut blossom_packs: Option> = None;

if !git_server_refspecs.is_empty() {

let new_state = generate_updated_state(git_repo, &existing_state, &git_server_refspecs)?;

+ let blossom_hashes = if repo_ref.git_server.contains(&"blossom".to_string()) {

+ let (blossom_hashes, packs) = create_blossom_packs(&new_state, git_repo)?;

+ blossom_packs = Some(packs);

+ blossom_hashes

+ } else {

+ HashSet::new()

+ };

- let new_repo_state =

- RepoState::build(repo_ref.identifier.clone(), new_state, &signer).await?;

+ let new_repo_state = RepoState::build(

+ repo_ref.identifier.clone(),

+ new_state,

+ blossom_hashes,

+ &signer,

+ )

+ .await?;

events.push(new_repo_state.event);

@@ -325,6 +355,13 @@ pub async fn run_push(

// TODO make async - check gitlib2 callbacks work async

+ if let Some(packs) = blossom_packs {

+ // TODO: upload blossom packs

+ for (_hash, _pack) in packs {

+ // blossom::upload(pack)

+ }

+ }

+

for (git_server_url, remote_refspecs) in remote_refspecs {

let remote_refspecs = remote_refspecs

.iter()

@@ -863,6 +900,71 @@ fn generate_updated_state(

Ok(new_state)

}

+fn create_blossom_packs(

+ state: &HashMap,

+ git_repo: &Repo,

+) -> Result<(HashSet, HashMap)> {

+ let mut blossom_hashes = HashSet::new();

+ let mut blossom_packs = HashMap::new();

+ for commit_id in state.values() {

+ if let Ok(oid) = Oid::from_str(commit_id) {

+ if let Ok(commit) = git_repo.git_repo.find_commit(oid) {

+ let height = get_height(&commit, git_repo)?;

+ let mut revwalk = git_repo.git_repo.revwalk()?;

+ revwalk.push(oid)?;

+ let mut counter = 0;

+ for pack_size in split_into_powers_of_2(height) {

+ let mut pack = git_repo.git_repo.packbuilder()?;

+ while counter < pack_size {

+ if let Some(oid) = revwalk.next() {

+ pack.insert_commit(oid?)?;

+ counter += 1;

+ }

+ }

+ let mut buffer = Buf::new();

+ pack.write_buf(&mut buffer)?;

+ let hash = buffer_to_sha256_hash(&buffer);

+ blossom_hashes.insert(hash);

+ blossom_packs.insert(hash, buffer);

+ counter = 0;

+ }

+ }

+ }

+ }

+ Ok((blossom_hashes, blossom_packs))

+}

+

+fn get_height(commit: &Commit, git_repo: &Repo) -> Result {

+ let mut revwalk = git_repo.git_repo.revwalk()?;

+ revwalk.push(commit.id())?;

+ Ok(u32::try_from(revwalk.count())?)

+}

+

+fn split_into_powers_of_2(height: u32) -> Vec {

+ let mut powers = Vec::new();

+ let mut remaining = height;

+

+ // Decompose the height into powers of 2

+ for i in (0..32).rev() {

+ let power = 1 << i; // Calculate 2^i

+ while remaining >= power {

+ powers.push(power);

+ remaining -= power;

+ }

+ }

+

+ powers

+}

+

+fn buffer_to_sha256_hash(buffer: &Buf) -> sha256::Hash {

+ let mut hasher = Sha256::new();

+ hasher.update(buffer.as_ref());

+ let hash = hasher

+ .finalize()

+ .to_hex_string(nostr_sdk::hashes::hex::Case::Lower);

+ sha256::Hash::from_str(&hash).unwrap()

+}

+

async fn get_merged_status_events(

term: &console::Term,

repo_ref: &RepoRef,

@@ -1186,6 +1288,7 @@ trait BuildRepoState {

async fn build(

identifier: String,

state: HashMap,

+ blossom: HashSet,

signer: &NostrSigner,

) -> Result;

}

@@ -1193,6 +1296,7 @@ impl BuildRepoState for RepoState {

async fn build(

identifier: String,

state: HashMap,

+ blossom: HashSet,

signer: &NostrSigner,

) -> Result {

let mut tags = vec![Tag::identifier(identifier.clone())];

@@ -1202,10 +1306,20 @@ impl BuildRepoState for RepoState {

vec![value.clone()],

));

}

+ if !blossom.is_empty() {

+ tags.push(Tag::custom(

+ nostr_sdk::TagKind::Custom("blossom".into()),

+ blossom

+ .iter()

+ .map(std::string::ToString::to_string)

+ .collect::>(),

+ ));

+ }

let event = sign_event(EventBuilder::new(STATE_KIND, "", tags), signer).await?;

Ok(RepoState {

identifier,

state,

+ blossom,

event,

})

}

diff --git a/src/lib/repo_state.rs b/src/lib/repo_state.rs

index c3a7606..19e78b6 100644

--- a/src/lib/repo_state.rs

+++ b/src/lib/repo_state.rs

@@ -1,11 +1,17 @@

-use std::collections::HashMap;

+use std::{

+ collections::{HashMap, HashSet},

+ str::FromStr,

+};

use anyhow::{Context, Result};

use git2::Oid;

+use nostr_sdk::hashes::sha256::Hash;

+#[derive(Clone)]

pub struct RepoState {

pub identifier: String,

pub state: HashMap,

+ pub blossom: HashSet,

pub event: nostr::Event,

}

@@ -14,6 +20,7 @@ impl RepoState {

state_events.sort_by_key(|e| e.created_at);

let event = state_events.first().context("no state events")?;

let mut state = HashMap::new();

+ let mut blossom = HashSet::new();

for tag in event.tags.iter() {

if let Some(name) = tag.as_slice().first() {

if ["refs/heads/", "refs/tags", "HEAD"]

@@ -26,6 +33,13 @@ impl RepoState {

}

}

}

+ if name.eq("blossom") {

+ for s in tag.clone().to_vec() {

+ if let Ok(hash) = Hash::from_str(&s) {

+ blossom.insert(hash);

+ }

+ }

+ }

}

}

Ok(RepoState {

@@ -35,6 +49,7 @@ impl RepoState {

.context("existing event must have an identifier")?

.to_string(),

state,

+ blossom,

event: event.clone(),

})

}

--

libgit2 1.8.1

Thanks for the upload!

Replying to Avatar Jurjen de Vries

The Nostr stand at FOSDEM is approved 🎉

I feel honored to present Nostr there 1 & 2 February 2025 with nostr:nprofile1qqsqvcu68pkfcyq5y9mz9n9u7sys33835rpnuglc6mtg7j4lv40c7ugpzemhxue69uhhyetvv9ujuvrcvd5xzapwvdhk6qg5waehxw309aex2mrp0yhxgctdw4eju6t0qyt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueq93artg nostr:nprofile1qqst32wlsgvqsnjfpkygxs4f6jyt0nc0kg935xdevwlv668dd26uh0gpzemhxue69uhkummnw3ezuumvda6xs7fwwa5kuqgkwaehxw309aex2mrp0yhxummnw3ezucnpdejqz8thwden5te0dehhxarj94c82c3wwajkcmr0wfjx2u3wdejhg3qrxjx nostr:nprofile1qqsfmd476kacwlqe920d9qrwazqrxpm3flwy85p2y3sj50qcexcvfmcpzfmhxue69uhhqatjwpkx2urpvuhx2ucpzemhxue69uhhyetvv9ujuurjd9kkzmpwdejhgqgkwaehxw309ahx7um5wghrs6edd3skytnrdaksxfatgv nostr:nprofile1qqspchlne2kdsskqrh9g7duzxxckv963d5s5mf6u0t4th60pal5upaspzamhxue69uhhyetvv9ujumn0wd68ytnzv9hxgtcpremhxue69uhkummnw3ez6ur4vgh8wetvd3hhyer9wghxuet59uq3qamnwvaz7tmwdaehgu3wd4hk6tc5kgfql .

https://fosdem.org/2025/news/2024-11-16-stands-announced/

We hope to see many of you in Brussels next year and especially to meet many open source fans, onboarding them and have Nostr expanded in other FOSS initiatives as well.

Ps. Thanks to nostr:nprofile1qqs09z9zyjnpkump42wugx5s4w529hl523xmp0pcvu5wvw9jrkshjtqpp4mhxue69uhkummn9ekx7mqpz4mhxue69uhk2er9dchxummnw3ezumrpdejqz9rhwden5te0wfjkccte9ejxzmt4wvhxjmcpeddte nostr:nprofile1qqs9afryspzmk8ljyfj4mhfkumwwmhzrtyxzvzgvfp477w80g5x6t0gpz4mhxue69uhhyetvv9ujuerpd46hxtnfduhs8h8rfc nostr:nprofile1qqs8d3c64cayj8canmky0jap0c3fekjpzwsthdhx4cthd4my8c5u47spzfmhxue69uhhqatjwpkx2urpvuhx2ucpz3mhxue69uhhyetvv9ujuerpd46hxtnfduq3vamnwvaz7tmjv4kxz7fwdehhxtnnda3kjctvll3q2p for their support with the submission document.

#FOSDEM #FOSDEM202 #grownostr #foss #opensource

Congrats! Nice job!