Skip to content
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

Relocate transaction verification #1507

Merged
Merged
Show file tree
Hide file tree
Changes from 95 commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
1d0ef09
Merge pull request #13 from neo-project/master
Qiao-Jin Mar 19, 2020
b14a589
Relocate transaction verifcation
Mar 20, 2020
e81cc6b
Merge pull request #17 from neo-project/master
Qiao-Jin Mar 23, 2020
915794e
Merge pull request #23 from neo-project/master
Qiao-Jin Mar 24, 2020
58b6731
Merge pull request #29 from neo-project/master
Qiao-Jin Mar 24, 2020
df5a99f
Merge branch 'master' of https://github.com/neo-project/neo into neo-…
Mar 25, 2020
28e3f48
Merge branch 'neo-project-master' into relocate_transaction_verification
Mar 25, 2020
9f2f7c6
Code optimization
Mar 25, 2020
241a92d
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Mar 27, 2020
ab4bb26
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Mar 27, 2020
fcaf7e4
Seperate sender fee check from transaction verification
Mar 30, 2020
2cfa56b
Merge branch 'relocate_transaction_verification' of https://github.co…
Mar 30, 2020
f7ba395
Format modification
Mar 30, 2020
eedb714
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Mar 31, 2020
b9f3a46
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Apr 2, 2020
3828ab2
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Apr 3, 2020
e407aad
Function rename and add parallel strategy
Apr 3, 2020
382605e
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Apr 3, 2020
6896500
Code optimization
Apr 6, 2020
b3b8c25
Code optimization
Apr 7, 2020
27ef0af
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Apr 8, 2020
0173cd3
Code optimization
Apr 8, 2020
78b304f
Format optimization
Apr 8, 2020
eb6f41f
Code optimization
Apr 8, 2020
35d7995
Merge branch 'master' of https://github.com/neo-project/neo into neo-…
Apr 10, 2020
08fa2a2
Merge branch 'neo-project-master' into relocate_transaction_verification
Apr 10, 2020
e65623a
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Apr 13, 2020
1e63267
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Apr 20, 2020
a0dcaf0
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Apr 26, 2020
7b605af
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Apr 27, 2020
4dad4d0
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin May 6, 2020
729d2ce
Fix VerifyWitnesses
May 6, 2020
fcc3c12
Revert "Fix VerifyWitnesses"
May 6, 2020
e578754
Rewrite verify_witness and corresponding logic
May 7, 2020
d228a51
code format
May 7, 2020
c08dc91
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin May 7, 2020
51e785c
Add statedependent to witness
May 9, 2020
a494053
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin May 9, 2020
83ee355
Code optimization
May 9, 2020
5c10326
Update src/neo/Network/P2P/Payloads/Witness.cs
Qiao-Jin May 9, 2020
f78503e
Update src/neo/Network/P2P/Payloads/Witness.cs
Qiao-Jin May 9, 2020
64d2a3f
Update src/neo/Network/P2P/Payloads/Witness.cs
Qiao-Jin May 9, 2020
5bea75d
Revert "Update src/neo/Network/P2P/Payloads/Witness.cs"
May 9, 2020
a4b38f0
Revert "Update src/neo/Network/P2P/Payloads/Witness.cs"
May 9, 2020
f119e18
Revert "Update src/neo/Network/P2P/Payloads/Witness.cs"
May 9, 2020
47567ae
optimize Witness
May 9, 2020
e0a5752
optimize witness and IVerifiable.verifyWitness
May 9, 2020
406e1d0
fix tx.Verify
May 9, 2020
116b59a
optimize code
May 9, 2020
fb9853a
optimize tx.GetScriptHashesForVerifying
May 9, 2020
b8c139e
Remove verifyForEachBlock
May 9, 2020
33a70fc
add VerifyResult.InvalidWitness
May 9, 2020
e263a06
Disallow witness.verificationScript to access the snapshot
May 9, 2020
2016da9
Optimize tx.VerifyStateDependent and verifiable.VerifyWitness
May 9, 2020
0bd4479
format
May 9, 2020
8666976
fix VerifyWitness
May 10, 2020
4f832ba
optimize tx.verify
May 10, 2020
5d1a218
optimize verifywitness
May 10, 2020
de81ddd
reset InteropService
May 11, 2020
0638e0b
add UT
May 11, 2020
4d1e1ac
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin May 12, 2020
9696c6a
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin May 15, 2020
c32f0fa
Split func OnInventoryReceived to avoid dirty write
May 15, 2020
be04b26
Merge branch 'master' into relocate_transaction_verification
shargon May 15, 2020
f9f2661
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin May 18, 2020
80ffb08
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin May 19, 2020
c198d6a
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin May 26, 2020
f3a5390
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin May 27, 2020
7ab56c3
Renew UT
May 27, 2020
235c9b9
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Jun 3, 2020
689d269
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Jul 10, 2020
a06c26a
Merge branch 'local_master' into relocate_transaction_verification
Aug 7, 2020
9d81c55
Check transaction size before creating task
Aug 7, 2020
13df078
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Aug 7, 2020
151dbac
Add missing note
Aug 7, 2020
1e76ed3
Merge branch 'relocate_transaction_verification' of https://github.co…
Aug 7, 2020
0ab3d71
Fix gas
shargon Aug 7, 2020
c8be765
Re-fix
shargon Aug 7, 2020
8f9bd7e
Merge branch 'master' into relocate_transaction_verification
shargon Aug 7, 2020
868ff31
Redefine WitnessFlag
Aug 7, 2020
a77ea11
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Aug 10, 2020
5288f27
Change multi task to actor pool
Aug 12, 2020
8c6ce68
Format correction
Aug 12, 2020
1320c78
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Aug 12, 2020
16fb3de
Update Transaction.cs
erikzhang Aug 13, 2020
d9c80ec
Rename
erikzhang Aug 13, 2020
90027d9
Update Witness.cs
erikzhang Aug 13, 2020
06e5d19
Merge branch 'master' into relocate_transaction_verification
Qiao-Jin Aug 13, 2020
f3b691a
Public transaction router
Aug 13, 2020
e6880d6
Fix and optimize
erikzhang Aug 14, 2020
c944e86
Move namespace
erikzhang Aug 14, 2020
cd0cd41
Move namespace
erikzhang Aug 14, 2020
3811cf6
Optimize
erikzhang Aug 14, 2020
f079a0f
Use the correct CallFlags
erikzhang Aug 14, 2020
55e3597
Merge branch 'master' into relocate_transaction_verification
erikzhang Aug 14, 2020
ea94018
Merge branch 'master' into relocate_transaction_verification
shargon Aug 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 45 additions & 16 deletions src/neo/Ledger/Blockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class Import { public IEnumerable<Block> Blocks; public bool Verify = tru
public class ImportCompleted { }
public class FillMemoryPool { public IEnumerable<Transaction> Transactions; }
public class FillCompleted { }
internal class PreverifyCompleted { public Transaction Transaction; public VerifyResult Result; public bool Relay; }
public class RelayResult { public IInventory Inventory; public VerifyResult Result; }

public static readonly uint MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock;
Expand Down Expand Up @@ -58,6 +59,7 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu
private const int MaxTxToReverifyPerIdle = 10;
private static readonly object lockObj = new object();
private readonly NeoSystem system;
private readonly IActorRef txrouter;
private readonly List<UInt256> header_index = new List<UInt256>();
private uint stored_header_count = 0;
private readonly Dictionary<UInt256, Block> block_cache = new Dictionary<UInt256, Block>();
Expand Down Expand Up @@ -103,6 +105,7 @@ static Blockchain()
public Blockchain(NeoSystem system, IStore store)
{
this.system = system;
this.txrouter = Context.ActorOf(TransactionRouter.Props(system));
this.MemPool = new MemoryPool(system, ProtocolSettings.Default.MemoryPoolMaxTransactions);
this.Store = store;
this.View = new ReadOnlyView(store);
Expand Down Expand Up @@ -302,20 +305,15 @@ private void OnFillMemoryPool(IEnumerable<Transaction> transactions)

private void OnInventory(IInventory inventory, bool relay = true)
{
RelayResult rr = new RelayResult
VerifyResult result = inventory switch
{
Inventory = inventory,
Result = inventory switch
{
Block block => OnNewBlock(block),
Transaction transaction => OnNewTransaction(transaction),
_ => OnNewInventory(inventory)
}
Block block => OnNewBlock(block),
Transaction transaction => OnNewTransaction(transaction),
_ => OnNewInventory(inventory)
};
if (relay && rr.Result == VerifyResult.Succeed)
if (relay && result == VerifyResult.Succeed)
system.LocalNode.Tell(new LocalNode.RelayDirectly { Inventory = inventory });
Sender.Tell(rr);
Context.System.EventStream.Publish(rr);
SendRelayResult(inventory, result);
}

private VerifyResult OnNewBlock(Block block)
Expand Down Expand Up @@ -360,6 +358,14 @@ private VerifyResult OnNewTransaction(Transaction transaction)
return MemPool.TryAdd(transaction, currentSnapshot);
}

private void OnPreverifyCompleted(PreverifyCompleted task)
{
if (task.Result == VerifyResult.Succeed)
OnInventory(task.Transaction, task.Relay);
else
SendRelayResult(task.Transaction, task.Result);
}

protected override void OnReceive(object message)
{
switch (message)
Expand All @@ -373,22 +379,34 @@ protected override void OnReceive(object message)
case Block block:
OnInventory(block, false);
break;
case Transaction tx:
OnTransaction(tx, true);
break;
case Transaction[] transactions:
{
// This message comes from a mempool's revalidation, already relayed
foreach (var tx in transactions) OnInventory(tx, false);
break;
}
// This message comes from a mempool's revalidation, already relayed
foreach (var tx in transactions) OnTransaction(tx, false);
break;
case IInventory inventory:
OnInventory(inventory);
break;
case PreverifyCompleted task:
OnPreverifyCompleted(task);
break;
case Idle _:
if (MemPool.ReVerifyTopUnverifiedTransactionsIfNeeded(MaxTxToReverifyPerIdle, currentSnapshot))
Self.Tell(Idle.Instance, ActorRefs.NoSender);
break;
}
}

private void OnTransaction(Transaction tx, bool relay)
{
if (ContainsTransaction(tx.Hash))
SendRelayResult(tx, VerifyResult.AlreadyExists);
else
txrouter.Tell(new TransactionRouter.Task { Transaction = tx, Relay = relay }, Sender);
}

private void Persist(Block block)
{
using (SnapshotView snapshot = GetSnapshot())
Expand Down Expand Up @@ -507,6 +525,17 @@ private void SaveHeaderHashList(SnapshotView snapshot = null)
}
}

private void SendRelayResult(IInventory inventory, VerifyResult result)
{
RelayResult rr = new RelayResult
{
Inventory = inventory,
Result = result
};
Sender.Tell(rr);
Context.System.EventStream.Publish(rr);
}

private void UpdateCurrentSnapshot()
{
Interlocked.Exchange(ref currentSnapshot, GetSnapshot())?.Dispose();
Expand Down
4 changes: 2 additions & 2 deletions src/neo/Ledger/MemoryPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ internal VerifyResult TryAdd(Transaction tx, StoreView snapshot)
_txRwLock.EnterWriteLock();
try
{
VerifyResult result = tx.Verify(snapshot, VerificationContext);
VerifyResult result = tx.VerifyStateDependent(snapshot, VerificationContext);
if (result != VerifyResult.Succeed) return result;

_unsortedTransactions.Add(tx.Hash, poolItem);
Expand Down Expand Up @@ -425,7 +425,7 @@ private int ReverifyTransactions(SortedSet<PoolItem> verifiedSortedTxPool,
// Since unverifiedSortedTxPool is ordered in an ascending manner, we take from the end.
foreach (PoolItem item in unverifiedSortedTxPool.Reverse().Take(count))
{
if (item.Tx.VerifyForEachBlock(snapshot, VerificationContext) == VerifyResult.Succeed)
if (item.Tx.VerifyStateDependent(snapshot, VerificationContext) == VerifyResult.Succeed)
{
reverifiedItems.Add(item);
VerificationContext.AddTransaction(item.Tx);
Expand Down
35 changes: 35 additions & 0 deletions src/neo/Ledger/TransactionRouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Akka.Actor;
using Akka.Routing;
using Neo.Network.P2P.Payloads;
using System;

namespace Neo.Ledger
{
internal class TransactionRouter : UntypedActor
{
public class Task { public Transaction Transaction; public bool Relay; }

private readonly IActorRef blockchain;

public TransactionRouter(NeoSystem system)
{
this.blockchain = system.Blockchain;
}

protected override void OnReceive(object message)
{
if (!(message is Task task)) return;
blockchain.Tell(new Blockchain.PreverifyCompleted
{
Transaction = task.Transaction,
Result = task.Transaction.VerifyStateIndependent(),
Relay = task.Relay
}, Sender);
}

internal static Props Props(NeoSystem system)
{
return Akka.Actor.Props.Create(() => new TransactionRouter(system)).WithRouter(new SmallestMailboxPool(Environment.ProcessorCount));
}
}
}
29 changes: 16 additions & 13 deletions src/neo/Network/P2P/Payloads/Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ bool IInventory.Verify(StoreView snapshot)
return Verify(snapshot, null) == VerifyResult.Succeed;
}

public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, TransactionVerificationContext context)
public virtual VerifyResult VerifyStateDependent(StoreView snapshot, TransactionVerificationContext context)
{
if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement)
return VerifyResult.Expired;
Expand All @@ -294,24 +294,27 @@ public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, TransactionVe
foreach (TransactionAttribute attribute in Attributes)
if (!attribute.Verify(snapshot, this))
return VerifyResult.Invalid;
if (hashes.Length != Witnesses.Length) return VerifyResult.Invalid;
for (int i = 0; i < hashes.Length; i++)
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
{
if (Witnesses[i].VerificationScript.Length > 0) continue;
if (snapshot.Contracts.TryGet(hashes[i]) is null) return VerifyResult.Invalid;
}
long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot);
if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.StateDependent))
return VerifyResult.Invalid;
return VerifyResult.Succeed;
}

public virtual VerifyResult VerifyStateIndependent()
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
{
if (Size > MaxTransactionSize)
return VerifyResult.Invalid;
if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StateIndependent))
return VerifyResult.Invalid;
return VerifyResult.Succeed;
}

public virtual VerifyResult Verify(StoreView snapshot, TransactionVerificationContext context)
{
VerifyResult result = VerifyForEachBlock(snapshot, context);
VerifyResult result = VerifyStateIndependent();
if (result != VerifyResult.Succeed) return result;
if (Size > MaxTransactionSize) return VerifyResult.Invalid;
long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot);
if (net_fee < 0) return VerifyResult.InsufficientFunds;
if (!this.VerifyWitnesses(snapshot, net_fee)) return VerifyResult.Invalid;
return VerifyResult.Succeed;
result = VerifyStateDependent(snapshot, context);
return result;
}

public StackItem ToStackItem(ReferenceCounter referenceCounter)
Expand Down
4 changes: 4 additions & 0 deletions src/neo/Network/P2P/Payloads/Witness.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class Witness : ISerializable
public byte[] InvocationScript;
public byte[] VerificationScript;

internal long GasConsumed { get; set; }

private UInt160 _scriptHash;
public virtual UInt160 ScriptHash
{
Expand All @@ -24,6 +26,8 @@ public virtual UInt160 ScriptHash
}
}

public bool StateDependent => VerificationScript.Length == 0;
erikzhang marked this conversation as resolved.
Show resolved Hide resolved

public int Size => InvocationScript.GetVarSize() + VerificationScript.GetVarSize();

void ISerializable.Deserialize(BinaryReader reader)
Expand Down
16 changes: 11 additions & 5 deletions src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,19 @@ private void OnGetHeadersMessageReceived(GetBlockByIndexPayload payload)

private void OnInventoryReceived(IInventory inventory)
{
system.TaskManager.Tell(inventory);
if (inventory is Transaction transaction)
system.Consensus?.Tell(transaction);
system.Blockchain.Tell(inventory, ActorRefs.NoSender);
pendingKnownHashes.Remove(inventory.Hash);
knownHashes.Add(inventory.Hash);
if (inventory is Block b) UpdateLastBlockIndex(b.Index, false);
system.TaskManager.Tell(inventory);
system.Blockchain.Tell(inventory, ActorRefs.NoSender);
switch (inventory)
{
case Transaction transaction:
system.Consensus?.Tell(transaction);
break;
case Block block:
UpdateLastBlockIndex(block.Index, false);
break;
}
}

private void OnInvMessageReceived(InvPayload payload)
Expand Down
16 changes: 13 additions & 3 deletions src/neo/SmartContract/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public static UInt160 ToScriptHash(this ReadOnlySpan<byte> script)
return new UInt160(Crypto.Hash160(script));
}

internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas)
internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas, WitnessFlag filter = WitnessFlag.All)
{
if (gas < 0) return false;
if (gas > MaxVerificationGas) gas = MaxVerificationGas;
Expand All @@ -146,6 +146,14 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap
if (hashes.Length != verifiable.Witnesses.Length) return false;
for (int i = 0; i < hashes.Length; i++)
{
WitnessFlag flag = verifiable.Witnesses[i].StateDependent ? WitnessFlag.StateDependent : WitnessFlag.StateIndependent;
if (!filter.HasFlag(flag))
{
gas -= verifiable.Witnesses[i].GasConsumed;
if (gas < 0) return false;
continue;
}

int offset;
ContractMethodDescriptor init = null;
byte[] verification = verifiable.Witnesses[i].VerificationScript;
Expand All @@ -164,14 +172,16 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap
if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false;
offset = 0;
}
using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot.Clone(), gas))
using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot?.Clone(), gas))
{
ExecutionContext context = engine.LoadScript(verification, CallFlags.None, offset);
CallFlags callFlags = verifiable.Witnesses[i].StateDependent ? CallFlags.AllowStates : CallFlags.None;
ExecutionContext context = engine.LoadScript(verification, callFlags, offset);
if (init != null) engine.LoadContext(context.Clone(init.Offset), false);
engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None);
if (engine.Execute() == VMState.FAULT) return false;
if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return false;
gas -= engine.GasConsumed;
verifiable.Witnesses[i].GasConsumed = engine.GasConsumed;
}
}
return true;
Expand Down
15 changes: 15 additions & 0 deletions src/neo/SmartContract/WitnessFlag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Neo.SmartContract
{
[Flags]
internal enum WitnessFlag : byte
{
None = 0,

StateIndependent = 0b00000001,
StateDependent = 0b00000010,

All = StateIndependent | StateDependent
}
}
Loading