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

Enable converting between public keys, script hashes and address #1428

Merged
merged 40 commits into from
Apr 8, 2020
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
36c1d16
Merge pull request #1 from neo-project/master
Qiao-Jin Oct 22, 2019
a1af198
Merge pull request #3 from neo-project/master
Qiao-Jin Oct 23, 2019
3b8b3fe
Merge pull request #6 from neo-project/master
Qiao-Jin Jan 21, 2020
e9cf99b
Enable converting between public keys, script hashes and address
Jan 21, 2020
2e5dbda
Add test cases
Jan 22, 2020
c42daf5
Merge branch 'master' into master
shargon Feb 5, 2020
914f831
Merge branch 'master' into master
Qiao-Jin Feb 12, 2020
7af4612
Code optimization
Feb 19, 2020
a5d6d89
Fee adjusting
Feb 19, 2020
f747e5a
Code optimization
Feb 19, 2020
111b5c7
Merge pull request #8 from neo-project/master
Qiao-Jin Feb 25, 2020
b7c04c5
Add comment
Feb 25, 2020
3afeb33
Merge branch 'master' into master
Qiao-Jin Mar 2, 2020
5117513
Merge branch 'master' into master
Qiao-Jin Mar 4, 2020
e7df5b1
Code optimization
Mar 9, 2020
4bf1d92
Merge pull request #9 from neo-project/master
Qiao-Jin Mar 13, 2020
b100d39
Code optimization
Mar 13, 2020
c7a332b
Merge from master
Mar 16, 2020
f452a68
Merge branch 'master' into master
Qiao-Jin Mar 16, 2020
9cbcfdc
Update InteropService.Contract.cs
erikzhang Mar 17, 2020
1962b94
Merge pull request #11 from neo-project/master
Qiao-Jin Mar 18, 2020
93fe8a7
Code optimization
Mar 18, 2020
e9f2214
Merge branch 'master' into master
shargon Mar 18, 2020
5efda66
Add wrong public key test cases
Mar 19, 2020
fa70610
Kick off new test
Mar 19, 2020
0e2a04b
format changing
Mar 19, 2020
bc2678c
Merge pull request #14 from neo-project/master
Qiao-Jin Mar 23, 2020
d306fb7
Merge branch 'master' into master
shargon Mar 23, 2020
57d1aeb
Merge pull request #21 from neo-project/master
Qiao-Jin Mar 24, 2020
5bb6d4e
Merge pull request #27 from neo-project/master
Qiao-Jin Mar 24, 2020
308b0f0
Merge branch 'master' into master
Qiao-Jin Mar 26, 2020
929aa41
Merge branch 'master' into master
shargon Mar 26, 2020
0a37b33
Code optimization
Mar 27, 2020
1913033
Merge branch 'master' into master
Qiao-Jin Mar 27, 2020
4a1c746
Merge branch 'master' into master
Qiao-Jin Mar 31, 2020
09b2852
Add comment
Apr 1, 2020
8700661
Merge branch 'master' into master
Qiao-Jin Apr 2, 2020
3075410
Merge branch 'master' into master
Qiao-Jin Apr 3, 2020
8eb00a7
Merge branch 'master' into master
Qiao-Jin Apr 3, 2020
c8fb1be
Merge branch 'master' into master
Qiao-Jin Apr 8, 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
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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decode the point for encode it later. Maybe in the future we should optimize this.

        {
            using (ScriptBuilder sb = new ScriptBuilder())
            {
                sb.EmitPush(publicKey.EncodePoint(true));
                sb.Emit(OpCode.PUSHNULL);
                sb.EmitSysCall(InteropService.Crypto.ECDsaVerify);
                return sb.ToArray();
            }
        }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures the correctness of the public key format.

But it brought me to the question, will this SYSCALL cause non-deterministic problems? Maybe some implementations will directly encode the incorrectly formatted public key, resulting in inconsistent results of contract execution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should ensure this with unit tests. And ensure that all implementations pass the same unit tests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Qiao-Jin could you add a comment for this possible issue in order to warn other implementations ? we must check first that the public key it's valid, before creating the script.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Qiao-Jin could you add a comment for this possible issue in order to warn other implementations ? we must check first that the public key it's valid, before creating the script.

Have added the comment.

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()
{
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
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