Skip to content

Commit

Permalink
Enable converting between public keys, script hashes and address (#1428)
Browse files Browse the repository at this point in the history
* Enable converting between public keys, script hashes and address

* Add test cases

* Code optimization

* Fee adjusting

* Code optimization

* Add comment

* Code optimization

* Code optimization

* Merge from master

* Update InteropService.Contract.cs

* Code optimization

* Add wrong public key test cases

* Kick off new test

* format changing

* Code optimization

* Add comment

Co-authored-by: Jin Qiao <jinqiao@neo.org>
Co-authored-by: Shargon <shargon@gmail.com>
Co-authored-by: erikzhang <erik@neo.org>
  • Loading branch information
4 people committed Apr 8, 2020
1 parent c0a4114 commit eaaf5d8
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/neo/SmartContract/InteropService.Contract.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.Ledger;
using Neo.Persistence;
Expand All @@ -20,6 +21,12 @@ public static class Contract
public static readonly InteropDescriptor CallEx = Register("System.Contract.CallEx", Contract_CallEx, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall);
public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All, CallFlags.None);

/// <summary>
/// Calculate corresponding account scripthash for given public key
/// Warning: check first that input public key is valid, before creating the script.
/// </summary>
public static readonly InteropDescriptor CreateStandardAccount = Register("System.Contract.CreateStandardAccount", Contract_CreateStandardAccount, 0_00010000, TriggerType.All, CallFlags.None);

private static long GetDeploymentPrice(EvaluationStack stack, StoreView snapshot)
{
int size = stack.Peek(0).GetByteLength() + stack.Peek(1).GetByteLength();
Expand Down Expand Up @@ -166,6 +173,14 @@ private static bool Contract_IsStandard(ApplicationEngine engine)
engine.CurrentContext.EvaluationStack.Push(isStandard);
return true;
}

private static bool Contract_CreateStandardAccount(ApplicationEngine engine)
{
if (!engine.TryPop(out ReadOnlySpan<byte> pubKey)) return false;
UInt160 scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubKey, ECCurve.Secp256r1)).ToScriptHash();
engine.Push(scriptHash.ToArray());
return true;
}
}
}
}
39 changes: 39 additions & 0 deletions tests/neo.UnitTests/SmartContract/UT_InteropService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,45 @@ public void TestContract_Destroy()

}

[TestMethod]
public void TestContract_CreateStandardAccount()
{
var engine = GetEngine(true, true);
byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes();

engine.CurrentContext.EvaluationStack.Push(data);
InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount).Should().BeTrue();
engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray());

data = "064b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes();
engine.CurrentContext.EvaluationStack.Push(data);
Assert.ThrowsException<FormatException>(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Invalid point encoding 6");

data = "024b817ef37f2fc3d4a33fe36687e599f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes();
engine.CurrentContext.EvaluationStack.Push(data);
Assert.ThrowsException<FormatException>(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Incorrect length for compressed encoding");

data = "02ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes();
engine.CurrentContext.EvaluationStack.Push(data);
Assert.ThrowsException<ArgumentException>(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("x value too large in field element");

data = "020fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes();
engine.CurrentContext.EvaluationStack.Push(data);
Assert.ThrowsException<ArithmeticException>(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Invalid point compression");

data = "044b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes();
engine.CurrentContext.EvaluationStack.Push(data);
Assert.ThrowsException<FormatException>(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Incorrect length for uncompressed/hybrid encoding");

data = "04ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes();
engine.CurrentContext.EvaluationStack.Push(data);
Assert.ThrowsException<ArgumentException>(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("x value too large in field element");

data = "040fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes();
engine.CurrentContext.EvaluationStack.Push(data);
Assert.ThrowsException<ArgumentException>(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("x value too large in field element");
}

public static void LogEvent(object sender, LogEventArgs args)
{
Transaction tx = (Transaction)args.ScriptContainer;
Expand Down

0 comments on commit eaaf5d8

Please sign in to comment.