-
Notifications
You must be signed in to change notification settings - Fork 1k
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 native Notary contract #3178
base: master
Are you sure you want to change the base?
Conversation
Close #2896. Use a stub for native Notary contract hash since this contract is not implemented yet. Thus, technically, NotaryAssisted attribute verification will always fail on real network until native Notary is implemented. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
…ribute Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Transactions network fee should be split between Primary node and Notary nodes. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Once Notary contract is implemented, this hash will be replaced by a proper Notary contract hash. The exact value won't be changed since Notary contract has constant hash as any other native contract. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
No functional changes, just a refactoring for better code readability. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Is this PR to be merged now or after next release? |
|
This contract has a
In this method, we verify that Here is an attack vector. A malicious notary can sign as many transactions as it wants and then publish at most 500 txs on chain while If it's not a malicious notary, someone could still get a chance to make the notary sign something multiple times and cache them then publish them at once. By the way, do you know how many core modules will be affected by 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.
I am not seeing the part of the code we discussed on Discord, @AnnaShaleva, you mentioned about a delegated powered notary signing.
"The contract itself don't send the transactions. It's a designated Notary node who is powered to send transactions on behalf of notary service users. "
I want to check that because it should be, at least, similar to the oracles design.
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
No functional changes, just a refactoring. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
To be able to process existing NeoFS chains that use Notary - yes, it's the last PR. But ideally in future we'd like to implement
It's a part of Notary service plugin. See the example implementation in https://github.com/nspcc-dev/neo-go/blob/master/pkg/services/notary/notary.go. |
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.
as @dusmart said , verify
method should be used with extreme caution. and is there a fork introduced?
That's a valid concern, but there are multiple ways to handle it, we'll get to it after #3175 merge. |
[ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] | ||
private bool Verify(ApplicationEngine engine, byte[] sig) | ||
{ | ||
Transaction tx = (Transaction)engine.ScriptContainer; |
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.
better to use as
just in case we change ScriptContainer
to something else like a block
. Applications using ApplicationEngine
will crash if the container
is not Transaction
type. Please change.
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.
we change ScriptContainer to something else like a block
It's impossible in this context. Contract verification always uses transaction as a script container, and if (for some reason) it's not true, then transaction will be FAULTed (which is the desired behaviour).
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.
Im asking is to
Transaction tx = engine.ScriptContainer as Transaction;
if (tx is null) return false;
No reason to crash. https://github.com/neo-project/proposals/blob/ff39b57eb67981b1ec7f0b244ec053aacdb7139a/nep-30.mediawiki#user-content-verify says it must return boolean
, not crash and must check System.Runtime.GetTrigger
Security is number one priority
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.
It's not a security issue, but for better user experience we can do it. Fixed.
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.
If it crashes it becomes caughtexception and someone can use trycatch
and push true to the stack in a signature.
tests/Neo.UnitTests/Extensions/Nep17NativeContractExtensions.cs
Outdated
Show resolved
Hide resolved
nFees += (long)nKeys + 1; | ||
if (tx.Sender == Hash) | ||
{ | ||
var payer = tx.Signers[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.
Won't it be out of range here?
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.
It won't, it is guaranteed by Notary's Verify
method.
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.
But if contrainer
is null
this will fail. Unless verify
is fixed with #3178 (comment)
[ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] | ||
private void SetMaxNotValidBeforeDelta(ApplicationEngine engine, uint value) | ||
{ | ||
if (value > engine.ProtocolSettings.MaxValidUntilBlockIncrement / 2 || value < ProtocolSettings.Default.ValidatorsCount) throw new FormatException(string.Format("MaxNotValidBeforeDelta cannot be more than {0} or less than {1}", engine.ProtocolSettings.MaxValidUntilBlockIncrement / 2, ProtocolSettings.Default.ValidatorsCount)); |
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 line is too long.
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.
Fixed.
Transaction tx = (Transaction)engine.ScriptContainer; | ||
if (tx.GetAttribute<NotaryAssisted>() is null) return false; |
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.
Transaction tx = (Transaction)engine.ScriptContainer; | |
if (tx.GetAttribute<NotaryAssisted>() is null) return false; | |
var tx = engine.ScriptContainer as Transaction; | |
if (tx?.GetAttribute<NotaryAssisted>() is null) return false; |
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 still think that it's needed? See #3178 (comment), please.
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 think it's better, impossible, but don't hurt and compatible with both cases
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.
Thank you @shargon #3178 (comment)
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.
Fixed.
Co-authored-by: Will <201105916+Wi1l-B0t@users.noreply.github.com>
No functional changes. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
var additionalParams = (Array)data; | ||
if (additionalParams.Count() != 2) throw new FormatException("`data` parameter should be an array of 2 elements"); |
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.
OnNEP17Payment
may be called by the contract.
So the data
may not be an Array
, and this line will throw an InvalidCastException
if not an Array
.
It's OK even if InvalidCastException
?
var additionalParams = (Array)data; | |
if (additionalParams.Count() != 2) throw new FormatException("`data` parameter should be an array of 2 elements"); | |
var additionalParams = data as Array; | |
if (additionalParams is null || additionalParams.Count() != 2) | |
throw new FormatException("`data` parameter should be an array of 2 elements"); | |
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 be object
type aka 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.
OnNEP17Payment may be called by the contract.
It's impossible because several lines below we have a check that ensures that calling context is GasToken contract.
So the data may not be an Array
But even when the caller is GasToken, it's possible that data has an unexpected format, so you're right here.
It's OK even if InvalidCastException?
Yes, it's OK, the main point here is that exception will be thrown anyway and execution is aborted. But from user's PoW it's always nice to see a well-formatted exception message instead of just InvalidCastException, hence I've updated this code.
{ | ||
long nFees = 0; | ||
ECPoint[] notaries = null; | ||
foreach (Transaction tx in engine.PersistingBlock.Transactions) |
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.
We can check if PersistingBlock
is null, neo express debugger fail with something similar in the past.
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 particular part of the code is ported from
foreach (Transaction tx in engine.PersistingBlock.Transactions) |
And we need to be unified with the behaviour. So we either fix it in both places or keep it as is.
{ | ||
var payer = tx.Signers[1]; | ||
var balance = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Deposit, payer.Account))?.GetInteroperable<Deposit>(); | ||
balance.Amount -= tx.SystemFee + tx.NetworkFee; |
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.
balance can be null
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.
Theoretically it's not much different from GAS contract being unable to write the fee off the sender balance, valid blocks shouldn't allow for that.
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.
Anyone can call ApplicationEngine
with whatever parameters they want. This needs to be fixed. This will crash testing environments. Safely is number one priority.
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.
It can't. For a single transaction it is guaranteed by verify
method of this contract:
neo/src/Neo/SmartContract/Native/Notary.cs
Line 117 in bb153eb
if (balance is null || balance.Amount.CompareTo(tx.NetworkFee + tx.SystemFee) < 0) return false; |
For multiple transactions in block it will be guaranteed by the mempool extension (not a part of this 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.
verify
is a CaughtException
. So catch it then what?
Throw FormatException instead of InvalidCastException on invalid data passed to OnNEP17Payment. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
6647a4f
to
516ca30
Compare
Return `false` in case if execution container for `verify` is not a transaction. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
if (deposit is null) return false; | ||
if (till < deposit.Till) return false; |
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.
if (deposit is null) return false; | |
if (till < deposit.Till) return false; | |
if (deposit is null || till < deposit.Till) return false; |
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.
Fixed.
{ | ||
/// <summary> | ||
/// A default value for maximum allowed NotValidBeforeDelta. It is set to be | ||
/// 20 rounds for 7 validators, a little more than half an hour for 15-seconds blocks. |
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.
A block will be 3 seconds. Does this const
value need to be adjusted?
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.
Let's keep the default value as it as is for now, it's just a default. And then we'll customize it for different networks, e.g. Mainnet is still running with 15-seconds blocks and NeoFS networks are running with 1-second blocks.
No functional changes, just a refactoring. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
@neo-project/core review, please. |
Description
Implement native Notary contract.
Close #2897.
Type of change
How Has This Been Tested?
Checklist: