-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Epic: Implement GENESISID
#135
Comments
|
Good question. I think we could do more homework on this. I suspect not. I suspect other chains make do with: 1. versioning in P2P handshake, 2. blacklisting/banning peers that send bad data, and 3. protocol objects that fail validation (without an explicit In the case of a blockchain protocol like Eth, each block must point to the previous block, and each block contains txs that contain chainids, etc., so there's no need to tag blocks explicitly with a chainid or genesisid. This is different for Spacemesh. We do get some of this "default protection" for objects like blocks, proposals, ATXs, etc. (see notes above) because they link to other objects that should be valid and in-context, but I'm not sure we have any other way to assert that, say, a smesher or nodeID wasn't reused on another chain (or fork). Geth does some ad hoc versioning of, e.g., blocks: here's an example where a legacy sync will reject post-merge blocks. And here's an example of a post-1559 chain rejecting pre-1559 blocks. These both resemble The logic Eth uses at the P2P layer is laid out in EIP-2124.
This is not an issue for
It'll be handled inside the principal account templates. The default (suggested, enshrined) template will handle it as part of the signature check as specified above; clients like smapp should include |
My open questions are here: https://community.spacemesh.io/t/where-to-bind-genesisid/284/2 but from my perspective this is basically done. |
just to clarify, i think this part should not be implemented for genesis, maybe it will make more sense later. which i still not certain because protocolid/vmid is something that can be stored in code.
|
Dumb question: if it's not stored in the database, where is it stored? |
the only reason to persist it is to protect administrator from changing this accidentally again, is it the case? are we going to have other immutable configuration parameters, such as genesis time, golden atx, hrp that can't be overwritten? if thats the case we can just persist whole immutable config part in a file and check that none of the those parameters were overwritten i initially thought that we can set all genesis parameters at compile time (one example of this approach is https://github.com/filecoin-project/lotus/tree/master/build) , but i guess genesis time may not be convenient to set this way |
I understand now, thanks. Yes, that's the plan, see spacemeshos/go-spacemesh#3348. Ideally we would let a developer run the same go-spacemesh code on multiple networks without recompiling, but I'm not totally opposed to this idea. |
I think this can't be implemented the way it is written. I initially missed that this spec suggests to append genesisid to the messages that are signed, not only hashes. It basically will require full buf allocation and copy every time when message is signed and verified. If message is 3kb - it will need 3kb + 32 for buf with genesis. There should be another way to do binding, that doesn't carry such huge cost. One option could be is to use ed25519ctx extention. Here https://github.com/oasisprotocol/curve25519-voi/blob/master/primitives/ed25519/ed25519.go#L130-L136 . i don't know if spacemesh lib for ed25519 supports that though. Also this is not something that can be completely optimized in the future. Whatever is done at genesis will have to be remain supported for old data in the chain. |
this part also surprises me
it means that every time when public key is recovered from signature we will have to additionaly compute node id using genesis id. what purpose does it serve, if message is signed in a separate domain? given that we are using separate domain for signatures.. |
what objects are actually prehashed before they are signed? i think this only true for transactions. ballots/activations are not prehashed another option could be to prehash every message that is signed (without allocating another huge memory buffer). fun Sign(pk PrivateKey, msg []byte) []byte {
hasher := hash.New()
hasher.Write(GENESISID)
hasher.Write(msg)
return ed25519.Sign(pk, hasher.Sum(nil))
} |
@lrettig @dshulyak @WilfredTA given the pending discussions I removed the split, let's first please finalize the design and then split to smaller work items. |
just to elaborate on my comments above. the proposed design doesn't take into account efficiency completely. some of what is proposed won't be possible to optimize away after genesis (such decisions like adding genesis id to payload before signing it). also lets consider how this will look in practice for verifying ballot:
doesn't it seem redundant? i can't believe that all of it is really necessary |
i propose the following changes:
|
@dshulyak see Where to bind (As Tal pointed out in future when we introduce multiple protocol versions, we will need to include these in ATXs, ballots, etc.) Note that this hash function can be made very efficient if necessary by compiling Regarding your ballot example:
Unless I'm misunderstanding, none of these steps are necessary. The |
@dshulyak speaking about that we also have spacemeshos/go-spacemesh#3327 that needs to be tackled :) |
i read that research topic, it has 3 conclusions:
what about requirement to bind node id to genesis id? there is no conclusion in the research topic about it. post is likely already bound to a particular node id, see spacemeshos/go-spacemesh#3327 (comment) . so we are missing commitment of the post to genesisid. do you want to merge both together? can we do it in a way that doesn't require computing node id from public key by hashing it together with genesisid when every message is received? based on my reading of the code we don't need to bind node id to genesis id, we need to:
this will ensure that post is generated by the node id for a particular genesis hash
spec implies that hashes are somehow needed for this, but they aren't. they are simply redundant (e.g don't do anything). maybe there was an assumption that we are signing hashes, and then we don't need to change code for signers. what sounds reasonable for me is either:
type BoundMessage[M Message] struct {
Genesis [32]byte
Message M
} or
|
@dshulyak you refer several times to the cost of hashing, e.g.,
but as discussed in the research forum thread, hashing can be made effectively zero cost by including the genesisid in the hash preimage. There are a few approaches here; one of them may require running a build script to compile in the change in a network-specific (genesisid-specific) fashion. |
I updated this epic and opened some related issues based on our conversation with @tal-m this week. Here are some of the changes I made:
@dshulyak @noamnelke @selfdual-brain please let me know if I've missed or misremembered anything. Back to you @WilfredTA |
this is totally different from what we agreed on the call. |
The spec says:
You proposed:
What's the difference? |
I thought that we agreed to prefix encoded tx that is passed to the hash function (https://github.com/spacemeshos/go-spacemesh/blob/develop/genvm/sdk/wallet/tx.go#L48-L49) it will be hash.Write(genesisid)
hash.Write(tx) // where tx is a concatenation of fields and edsigner still receives just a hash |
What is the difference in practice between signing the concatenation of It depends maybe on if there is a case where we want to recover GenesisID from the signature |
I don't have a strong preference on this, it feels like a question of semantics to me (does default verify() implementation use the modified ED signer or the unmodified signer?) that templates can override in future anyway. Let me know if I'm misunderstanding something. Will give it some more thought. |
in this case this is simpler. we are already hashing tx. adding genesisid into the hash won't require additional buffer or ed25519 library that supports streaming input for it to be efficient. but from my pow this is better simply because it is simpler. another thing is that we probably should be using ed25519ph (that uses HashEddsa as in https://www.rfc-editor.org/rfc/rfc8032). It skips internal round of hashing, and requires input to be already prehashed. and this case prehashed tx would be required. |
Based on spacemeshos/SMIPS#75, replaces #117 for genesis
genesis
section to config and ensure that it is immutablegenesis-extradata
(string with a max length of 255 chars.). Default value should bemainnet
.p2p.network-id
from config (it's superseded by the above and no longer necessary).genesis-time
is updated, when launching a new network (Add support for genesisID go-spacecraft#38)main.go
should receive and set a 20 byte hash (byte array) value calledcmd.GenesisID
. (SeeLDFLAGS
inMakefile
.)genesis-extradata
from config, zero-pad the string and turn it into a fixed-length byte array. It should then calculate the ID as follows:GENESISID := hash(genesis-time || genesis-extradata)
goldenATXID
toGENESISID
(node.go :: initServices
) and removegolden-atx
from the config file (note: in future we may want to do this the other way around, and include the golden ATX ID in the GENESISID)GENESISID
. For this we need POPS-VRF (POPS-VRF #168 POPS-VRF implementation #172), but that task is distinct and for the purposes of this task we may assume it's already in place.GENESISID
. Modifysigning/signer.go
to concatenateGENESISID
ontom
inSign
andVerify
. (note: VRF signer does not need to be updated since it should already factor in the smesher ID nonce as part of POPS-VRF)verify()
method should use the modified ED signer (which includesGENESISID
, as described above) (note: in future we may want to expose an unmodified signer to template code, but this isn't necessary for genesis)GENESISID
when signing a new tx, so theverify()
sig check passes (Add support for genesis ID smapp#949)cfg.NetworkID
, replace withGENESISID
in handshake. (Note: a malicious peer could still send invalid data after a handshake, so all of the other checks here are still required.)GENESISID
isn't gossipped, and that the peer that sent it is banned (gossip, sync)Notes/Things to look for:
GENESISID
- typically implicitly, via a signature check. Note that p2p IDs are not tied toGENESISID
, so there is no implicit check at the p2p layer. Checks must happen in higher level handlers or data structures and their signatures. To check: weak coin, beacon.GENESISID
.The text was updated successfully, but these errors were encountered: