-
Notifications
You must be signed in to change notification settings - Fork 12
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
AuRa randomness #52
AuRa randomness #52
Conversation
I have implemented signing in 1323ef7. You could use a similar approach. Since the code is so similar, it could probably be factored out into helper functions. |
As far as secrets are concerened: one option would be to store the data encrypted using an AEAD cipher with a symmetric key derived (via a hash function of some sort) from the secret signing key and some locally-obtained randomness. The data could then be stored on-blockchain, since it is useless to anyone who does not have this node’s signing key. The precise AEAD cipher is an implementation detail, and different nodes can use different ciphers. Of course, we could also use the local file system as well. The encryption is still a good idea. A full database is massive overkill ― a flat file is more than adequate, provided that it is protected with a lock of some sort. |
That'd make a nice helper function in
I don't think it's necessary to store this on the blockchain unless the intended punishment for not having the secret available is very draconian. The best "cryptography" is not telling anyone anything in the first place and any effort and additional risk here does not warrant the small benefit of the above case, in my opinion.
I believe we could even get away with just storing it as a field on some data structure for now. I did refrain from use the filesystem, because I felt dirty just randomly writing a file somewhere; I was hoping that parity would already provide capabilities. |
FYI, Parity uses different |
This looks pretty good. I haven't quite wrapped my head around the exact details of how and where these contracts will be used but I suspect that the usage of I think the best thing to do here is to squash and merge these changes now then continue to make needed changes on the |
I noticed, I used
My intention was that
No objections from me here. I assigned this to @afck to he sees it, but if someone wants to preempt this, I guess that's fine, too =). |
Looks great! Let's just make sure we're using tabs everywhere, then squash and merge. |
I replaced the spaces. From my side, I'm fine with squashing and merging, if @DemiMarie and @vkomenda are okay with it. We can do the integration in a separate PR. |
339128c
to
41a5b2d
Compare
I (hope I) Finally, I rebased and fixed a test compilation error. One test is still failing, though, and I don't know whether it has anything to do with this PR, because it doesn't even compile on the |
I'll try to deal with error handling |
OK, I'm pretty sure my code is also wrong: If I understand correctly, |
41a5b2d
to
4e7e838
Compare
I replaced my last commit and reverted some of the changes. |
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.
@afck, do you still see machine
and block
belonging in authority_round::BoundedContract
? I was trying to fit those elsewhere but your solution looked good.
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 agree that integration should be a separate task.
I don't think so: For our purposes, the whole |
…d87633a54a7444883b32687faf5b80bf`. The contract was compiled using solc `0.4.25+commit.59dbf8f1.Linux.g++` and formatted using [json_pp](https://packages.debian.org/stretch/libjson-pp-perl).
…by scheduling a transaction.
72c70c7
to
adcf4a2
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.
The code looks good, but there should be some more documentation, and the new code should be tested.
/// | ||
/// The process of generating random numbers is a simple finite state machine: | ||
/// | ||
/// + |
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 surrounded with ```text
and ```
// Currently the PoS contracts are setup in a way that only the system address can | ||
// commit hashes, so we need to sign "manually". | ||
let signature: Bytes = | ||
signer.sign(secret_hash).map_err(PhaseError::Sign)?.as_ref().into(); |
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.
Signatures should not be necessary here, as all transactions are signed by the private key corresponding to the address that sent them.
|
||
// We are now sure that we have the correct secret and can reveal it. | ||
let signature: Bytes = | ||
signer.sign(secret.into()).map_err(PhaseError::Sign)?.as_ref().into(); |
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.
Again, no signature should be necessary.
|
||
/// Perform a function call to an ethereum machine. | ||
/// | ||
/// Runs a constant function call on `client`. The `call` value can be serialized by calling any |
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.
Is there some reason this can only call a constant function? Presumably, it is because on-chain state cannot be updated synchronously, but this should be documented.
/// Causes `client` to schedule a call to the bound contract. The `call` value can be serialized | ||
/// by calling any api function generated by the `use_contract!` macro. | ||
pub fn schedule_service_transaction<D>(&self, call: (ethabi::Bytes, D)) -> Result<(), CallError> { | ||
// NOTE: The second item of `call` is actually meaningless, since the function will only be |
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 this function also take an asynchronous callback?
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 don't think it can: It creates a transaction and puts it in the queue.
(We don't need a callback right now, and adding that functionality would require deep changes to how Parity handles transactions in general.)
Thanks! I addressed your comments. Please take another look. |
I forgot to rebase before merging, sorry. |
👏 Thanks for merging! |
This is the pull request that implements most of issue #51, AuRa random numbers. The code here is well documented (shoutout to asciiflow) and should be very straightforward, I hope it makes for an entertaining read.
I divided the problem into three subtasks:
Contract interaction
That is, calling actual ethereum contracts from parity performing both, constant calls returning a value immediately, and transactional ones. I did look at the following code for inspiration and did assume that there is a
Client
instance available to perform these calls:To ease this, I added the
BoundContract
struct, which ties a client to a specific block and contract, making it possible to call these functions without much of a fuss. All code related to that can be found inethcore/src/engines/authority_round/util.rs
There might be a better way to accomplish this, but I found only ad-hoc implementations of something similar in other parts of the parity codebase. At the very least, this module neatly separates open questions about internal APIs from the business logic.
Actual business logic
The
ethcore/res/authority_round_random.json
file contains the ABI description for the relevant contracts, which are included using theuse_contract
macro. Runningcargo doc --all --document-private-items
turned out to be a real lifesaver here.The actual implementation for the randomness generation is inside the
./src/engines/authority_round/randomness.rs
, consisting of the finite state machineRandomnessPhase
. All its state is loaded from the blockchain itself, using theload()
function, which will determine the precise state the process is currently in.Once the
RandomnessPhase
has been loaded, theadvance()
method can be used to create the potentially necessary transactions for the process and apply them. Afteradvance()
has been called, the phase should be discarded (itusually is,
advance()
takes an ownedself
precisely for this reason).The only state that has to be managed externally is the generated secret. On the very first time the function is called,
None
can be passed as theOption<Secret>
, but every consecutive time the function is called, the return value of the last successful previous call should be passed in.The smart contract ABI used in this PR is from poanetwork/posdao-contracts@8d10a85. If anything changes, the ABI file must be manually updated here.
Still missing from the implementation (as indicated by the two
unimplemented!()
macros) is the signature generation and packing, I have not had the time to get around to this final puzzle piece (see the TODO for details).Parity integration
The actual integration is still missing, but should be doable in very few lines of code, provided one knows where to put it. In a function that is executed for every block mined by the validator, the following steps are necessary:
Option<Secret>
from storage/memory/elsewhere.BoundClient
instance with the latest block number and (hardcoded or configured) randomness contract address.RandomnessPhase::load
.RandomnessPhase::advance
.Option<Secret>
back to storage/memory/elsewhere.The specifics on how/where to store the
Option<Secret>
and what to do in case of errors depend greatly on where this integration code ends up, for this reason therandomness
module is not very opinionated about them.Compilation & Testing
The branch compiles without any errors, albeit plenty of unused code warnings. Tests fail, because the underlying starting point from the
aura-pos
branch did not test clean either.Since the actual integration is not done, the code has little influence on the rest of the system, it just presents two modules (
authority_round::util
andauthority_round::randomness
) that compile.The code is woefully undertested, due to its incompleteness. I would suggest making the underlying
aura-pos
branch testable again, then rebasing this branch, before adding tests.Still TODO
BoundContract
.rpc/src/v1/helpers/dispatch.rs:246
), removing the last twounimplemented!()
macro calls. If not, the implementation would probably nicely fit intoutil.rs
.