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

Update policy - Add maximum witness size (in bytes) #1020

Merged
merged 12 commits into from
Aug 21, 2019
122 changes: 121 additions & 1 deletion neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,62 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.IO;
using Neo.IO.Json;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.Wallets;
using Neo.Wallets.NEP6;
using System;
using System.IO;
using System.Linq;

namespace Neo.UnitTests.Network.P2P.Payloads
{
[TestClass]
public class UT_Witness
{
class DummyVerificable : IVerifiable
{
private UInt160 _hash;

public Witness[] Witnesses { get; set; }

public int Size => 1;

public DummyVerificable(UInt160 hash)
{
_hash = hash;
}

public void Deserialize(BinaryReader reader)
{
DeserializeUnsigned(reader);
Witnesses = reader.ReadSerializableArray<Witness>(16);
}

public void DeserializeUnsigned(BinaryReader reader)
{
reader.ReadByte();
}

public UInt160[] GetScriptHashesForVerifying(Snapshot snapshot)
{
return new UInt160[] { _hash };
}

public void Serialize(BinaryWriter writer)
{
SerializeUnsigned(writer);
writer.Write(Witnesses);
}

public void SerializeUnsigned(BinaryWriter writer)
{
writer.Write((byte)1);
}
}

Witness uut;

[TestInitialize]
Expand All @@ -22,6 +71,77 @@ public void InvocationScript_Get()
uut.InvocationScript.Should().BeNull();
}

private Witness PrepareDummyWitness(int maxAccounts)
{
var store = TestBlockchain.GetStore();
var wallet = TestUtils.GenerateTestWallet();
var snapshot = store.GetSnapshot();

// Prepare

var address = new WalletAccount[maxAccounts];
var wallets = new NEP6Wallet[maxAccounts];
var walletsUnlocks = new IDisposable[maxAccounts];

for (int x = 0; x < maxAccounts; x++)
{
wallets[x] = TestUtils.GenerateTestWallet();
walletsUnlocks[x] = wallets[x].Unlock("123");
address[x] = wallets[x].CreateAccount();
}

// Generate multisignature

var multiSignContract = Contract.CreateMultiSigContract(maxAccounts, address.Select(a => a.GetKey().PublicKey).ToArray());

for (int x = 0; x < maxAccounts; x++)
{
wallets[x].CreateAccount(multiSignContract, address[x].GetKey());
}

// Sign

var data = new ContractParametersContext(new DummyVerificable(multiSignContract.ScriptHash));

for (int x = 0; x < maxAccounts; x++)
{
Assert.IsTrue(wallets[x].Sign(data));
}

Assert.IsTrue(data.Completed);
return data.GetWitnesses()[0];
}

[TestMethod]
public void MaxSize_OK()
{
var witness = PrepareDummyWitness(10);

// Check max size

witness.Size.Should().Be(1003);
witness.InvocationScript.GetVarSize().Should().Be(653);
witness.VerificationScript.GetVarSize().Should().Be(350);

Assert.IsTrue(witness.Size <= 1024);

var copy = witness.ToArray().AsSerializable<Witness>();

CollectionAssert.AreEqual(witness.InvocationScript, copy.InvocationScript);
CollectionAssert.AreEqual(witness.VerificationScript, copy.VerificationScript);
}

[TestMethod]
public void MaxSize_Error()
{
var witness = PrepareDummyWitness(11);

// Check max size

Assert.IsTrue(witness.Size > 1024);
Assert.ThrowsException<FormatException>(() => witness.ToArray().AsSerializable<Witness>());
}

[TestMethod]
public void InvocationScript_Set()
{
Expand Down Expand Up @@ -73,4 +193,4 @@ public void ToJson()
Assert.AreEqual(json["verification"].AsString(), "202020");
}
}
}
}
7 changes: 5 additions & 2 deletions neo/Network/P2P/Payloads/Witness.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ public virtual UInt160 ScriptHash

void ISerializable.Deserialize(BinaryReader reader)
{
InvocationScript = reader.ReadVarBytes(65536);
VerificationScript = reader.ReadVarBytes(65536);
// This is designed to allow a MultiSig 10/10 (around 1003 bytes) ~1024 bytes
// Invocation = 10 * 64 + 10 = 650 ~ 664 (exact is 653)
InvocationScript = reader.ReadVarBytes(664);
// Verification = 10 * 33 + 10 = 340 ~ 360 (exact is 350)
VerificationScript = reader.ReadVarBytes(360);
}

void ISerializable.Serialize(BinaryWriter writer)
Expand Down