Skip to content

Commit

Permalink
Optimize BlockAccount (neo-project#1843)
Browse files Browse the repository at this point in the history
* Optimize

* Change to BinarySearch

* Fix index

* fix ut

* Update src/neo/SmartContract/Native/PolicyContract.cs

Co-authored-by: Erik Zhang <erik@neo.org>

Co-authored-by: Erik Zhang <erik@neo.org>
  • Loading branch information
2 people authored and cloud8little committed Jan 24, 2021
1 parent dccc905 commit 69fb0bc
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/neo/Network/P2P/Payloads/Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, TransactionVe
if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement)
return VerifyResult.Expired;
UInt160[] hashes = GetScriptHashesForVerifying(snapshot);
if (NativeContract.Policy.GetBlockedAccounts(snapshot).Intersect(hashes).Any())
if (NativeContract.Policy.IsAnyAccountBlocked(snapshot, hashes))
return VerifyResult.PolicyFail;
if (NativeContract.Policy.GetMaxBlockSystemFee(snapshot) < SystemFee)
return VerifyResult.PolicyFail;
Expand Down
20 changes: 20 additions & 0 deletions src/neo/SmartContract/Native/PolicyContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,25 @@ public UInt160[] GetBlockedAccounts(StoreView snapshot)
?? Array.Empty<UInt160>();
}

public bool IsAnyAccountBlocked(StoreView snapshot, params UInt160[] hashes)
{
if (hashes.Length == 0) return false;

var blockedList = snapshot.Storages.TryGet(CreateStorageKey(Prefix_BlockedAccounts))
?.GetSerializableList<UInt160>().ToArray()
?? Array.Empty<UInt160>();

if (blockedList.Length > 0)
{
foreach (var acc in hashes)
{
if (Array.BinarySearch(blockedList, acc) >= 0) return true;
}
}

return false;
}

[ContractMethod(0_03000000, CallFlags.AllowModifyStates)]
private bool SetMaxBlockSize(ApplicationEngine engine, uint value)
{
Expand Down Expand Up @@ -119,6 +138,7 @@ private bool BlockAccount(ApplicationEngine engine, UInt160 account)
if (accounts.Contains(account)) return false;
engine.Snapshot.Storages.GetAndChange(key);
accounts.Add(account);
accounts.Sort();
return true;
}

Expand Down
58 changes: 58 additions & 0 deletions tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,64 @@ public void Check_SetFeePerByte()
ret.GetInteger().Should().Be(1);
}

[TestMethod]
public void Check_BlockAccount()
{
var snapshot = Blockchain.Singleton.GetSnapshot();

// Fake blockchain

snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero };
snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero });

NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0));

// Without signature

var ret = NativeContract.Policy.Call(snapshot, "getBlockedAccounts");
ret.Should().BeOfType<VM.Types.Array>();
(ret as VM.Types.Array).Count.Should().Be(0);

// With signature

UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot);
ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr),
"blockAccount",
new ContractParameter(ContractParameterType.ByteArray) { Value = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01").ToArray() });
ret.Should().BeOfType<VM.Types.Boolean>();
ret.GetBoolean().Should().BeTrue();

// Same account
ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr),
"blockAccount",
new ContractParameter(ContractParameterType.ByteArray) { Value = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01").ToArray() });
ret.Should().BeOfType<VM.Types.Boolean>();
ret.GetBoolean().Should().BeFalse();

// Account B

ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr),
"blockAccount",
new ContractParameter(ContractParameterType.ByteArray) { Value = UInt160.Parse("0xb400ff00ff00ff00ff00ff00ff00ff00ff00ff01").ToArray() });
ret.Should().BeOfType<VM.Types.Boolean>();
ret.GetBoolean().Should().BeTrue();

// Check

NativeContract.Policy.IsAnyAccountBlocked(snapshot).Should().BeFalse();
NativeContract.Policy.IsAnyAccountBlocked(snapshot, UInt160.Zero).Should().BeFalse();
NativeContract.Policy.IsAnyAccountBlocked(snapshot, UInt160.Zero, UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01")).Should().BeTrue();
NativeContract.Policy.IsAnyAccountBlocked(snapshot, UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), UInt160.Zero).Should().BeTrue();
NativeContract.Policy.IsAnyAccountBlocked(snapshot, UInt160.Zero, UInt160.Parse("0xb400ff00ff00ff00ff00ff00ff00ff00ff00ff01")).Should().BeTrue();
NativeContract.Policy.IsAnyAccountBlocked(snapshot, UInt160.Parse("0xb400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), UInt160.Zero).Should().BeTrue();

ret = NativeContract.Policy.Call(snapshot, "getBlockedAccounts");
ret.Should().BeOfType<VM.Types.Array>();
(ret as VM.Types.Array).Count.Should().Be(2);
(ret as VM.Types.Array)[0].GetSpan().ToHexString().Should().Be("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4");
(ret as VM.Types.Array)[1].GetSpan().ToHexString().Should().Be("01ff00ff00ff00ff00ff00ff00ff00ff00ff00b4");
}

[TestMethod]
public void Check_Block_UnblockAccount()
{
Expand Down

0 comments on commit 69fb0bc

Please sign in to comment.