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
Implement broadcasting a pre-image #530
Conversation
Codecov Report
@@ Coverage Diff @@
## v0.x.x #530 +/- ##
==========================================
- Coverage 89.14% 88.14% -1.01%
==========================================
Files 59 58 -1
Lines 4285 4320 +35
==========================================
- Hits 3820 3808 -12
- Misses 465 512 +47
Continue to review full report at Codecov.
|
{ | ||
public Hash utxo_key; | ||
public Hash hash; | ||
public uint round; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an interesting approach. When we were originally talking about it, I had in mind that this would by block height, not round. Because the issue is that if you re-use the same utxo_key
(as you would), then you can do replay attacks.
Of course validation would fail, but you could potentially pretend a node sent you the wrong preimage data. We didn't factor any slashing rules that could be triggered by this tho.
A downside of using the block_height
is that it's harder to pre-emptively broadcast preimage as you don't know whe height at which it'll be included. But that can be dealt with when the enrollment is received.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case, this could use some documentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like accept your thought because it's more convenient to recognize the block to which the preimage is related. So, I could add the variable named start_block_height
into the Enrollment structure which is the block height where a validator is supposed to participate in validating. Then, The variable, round
of the PreimageInfo structure could be replaced with a variable like round_block_height
. How about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
start_block_height
Minor stylistic note: "height" is pretty unambiguous in blockchain code, so you can just use start_height
(because there's no other height that block height).
which is the block height where a validator is supposed to participate in validating
I'll have to double check, the exact flow, but bear in mind that if we go this way, it is an implicit value. What I mean is that, when you create an Enrollment
structure and sign it, you cannot know which start_height
you will be assigned, because it has to be accepted by the validators. Same goes for transactions, when you create a transaction, you cannot know at which height it will be.
Does that make sense ? Also, I think both approaches have their merits, so maybe let's have a whiteboarding session about it ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand what you're considering. After a bit of thought, I can use the enrolled_height
variable which is implemented by Henry. The value of enrolled_height + 1
will have the same value as what I want to have with the start_block_height
variable. It's good to have a whiteboarding session.
PreimageInfo preimage; | ||
auto round = 1000; | ||
assert(man.getPreimage(1000, preimage)); | ||
assert(preimage.hash == man.preimages[round-1]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should also test with 0
and > ValidatorCycleLength
{ | ||
public Hash utxo_key; | ||
public Hash hash; | ||
public uint round; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case, this could use some documentation
source/agora/consensus/Validation.d
Outdated
/// | ||
unittest | ||
{ | ||
uint CycleLength = 1008; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use const
if it isn't going to be modified
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, since you made it a constant in an earlier commit, can we just use it ?
source/agora/consensus/Validation.d
Outdated
*******************************************************************************/ | ||
|
||
public string isInvalidPreimageReason (const ref Hash preimage, const uint round, | ||
const ref Hash init_seed, immutable uint cycle_length) nothrow @safe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For value type, const
/ immutable
does not make sense. So just use uint
.
source/agora/consensus/Validation.d
Outdated
|
||
// check the pre-image has a right hash value | ||
Hash temp_hash = preimage; | ||
for (int i = round; i < cycle_length; i++) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (int i = round; i < cycle_length; i++) | |
for (uint i = round; i < cycle_length; i++) |
source/agora/network/NetworkClient.d
Outdated
|
||
***************************************************************************/ | ||
|
||
public void sendPreimage (PreimageInfo preimage) @trusted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public void sendPreimage (PreimageInfo preimage) @trusted | |
public void sendPreimage (ref PreimageInfo preimage) @trusted |
|
||
*******************************************************************************/ | ||
|
||
public struct PreimageInfo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be in consensus.data
source/agora/test/Base.d
Outdated
@@ -433,6 +433,12 @@ public interface TestAPI : API | |||
|
|||
/// | |||
public abstract Enrollment createEnrollmentData(); | |||
|
|||
/// | |||
public abstract PreimageInfo getNodePreimage(uint round); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public abstract PreimageInfo getNodePreimage(uint round); | |
public abstract PreimageInfo getNodePreimage (uint round); |
source/agora/api/Validator.d
Outdated
|
||
***************************************************************************/ | ||
|
||
public void sendPreimage (PreimageInfo preimage); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming wise, we have receiveEnvelope
but sendPreimage
. I don't mind either way but we should be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean changing the function name into a name like receivePreimage? If you do, changing the name is not a problem for me. I mean I can change the neme.
preimage_1 = node_1.getNodePreimage(1000); | ||
node_1.sendPreimage(preimage_1); | ||
auto preimage_2 = node_2.getValidatorPreimage(preimage_1.enroll_key); | ||
assert(preimage_1 == preimage_2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not black box testing. Adding 2 special methods means you aren't really testing the API.
A better test would be to send a pre-image and check if the (X) next block contains it.
Additionally you could filter the sendPreimage
function of a block to see if it propagates correctly even in the absence of the preimage in one block (but that depends on Henry's PR)/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My original approach is not to save pre-images into a block. It's stored only in the validator set table. A pre-image can be restored from another nodes if the database has been crashed. In that case, another API endpoint like getPreimage is needed with the getNodePreimage and getValidatorPreimage removed. Anyway the two functions could be confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is another approach about saving pre-images. It's to store the source value of the random seed encrypted with a node's private key into the Enrollment structure. With that, if the database crashed, the source value of the random seed used for enrollment can be restored from the chain.
029981c
to
2939554
Compare
***************************************************************************/ | ||
|
||
public bool getPreimage (uint round, out PreimageInfo preimage) | ||
@trusted nothrow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why @trusted
?
I will make a smaller PR including two commits of this PR and apply reviewer's suggestion in the new PR. And then, I will handle with the remaining commits of this PR which is not inluded in the new PR. |
4ae42f3
to
f56a3a2
Compare
Ready for review. |
c739564
to
0bde88c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not done reviewing, github won't let me continue because of a push.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed first commit.
{ | ||
() @trusted { | ||
this.db.execute("UPDATE validator_set SET preimage = ? " ~ | ||
"WHERE key = ?", buffer, preimage.enroll_key.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about memory allocation, toString()
allocates. Can use sformat
to write the entire string to a buffer before calling execute
.
|
||
// tests for revealing a pre-image | ||
auto preimage = node_1.getPreimage(1000); | ||
node_1.receivePreimage(preimage); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This node should already know about its own preimages. It is odd that it would need to send the preimage to itself in order to know about it, no?
Done with review. |
9c943dc
to
74c5006
Compare
The EnrollmentManger class must provide functions to add a piece of pre-image information and check existence of it for broadcasting preimage.
A Node reveals a pre-image information into the network. The broadcasting of a pre-image is processed through the gossip protocol.
74c5006
to
99f3c12
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, let's move forward with this.
@@ -43,6 +43,8 @@ | |||
module agora.api.Validator; | |||
|
|||
import agora.common.crypto.Key; | |||
import agora.common.Hash; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import agora.common.Hash; | |
import agora.common.Types; |
This PR is about broadcasting a pre-image and saving it into the validator set table.
#492