diff --git a/AntSharesCore/AntSharesCore.csproj b/AntSharesCore/AntSharesCore.csproj index a798bc91d8..4ec04c6c32 100644 --- a/AntSharesCore/AntSharesCore.csproj +++ b/AntSharesCore/AntSharesCore.csproj @@ -155,6 +155,7 @@ + diff --git a/AntSharesCore/Core/Scripts/ScriptEngine.cs b/AntSharesCore/Core/Scripts/ScriptEngine.cs index d420a67b0e..a8f1f951bd 100644 --- a/AntSharesCore/Core/Scripts/ScriptEngine.cs +++ b/AntSharesCore/Core/Scripts/ScriptEngine.cs @@ -39,13 +39,13 @@ public bool Execute() return Stack.Count == 1 && Stack.Pop(); } - private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) + private VMState ExecuteOp(ScriptOp opcode, BinaryReader opReader) { - if (opcode > ScriptOp.OP_16 && ++nOpCount > MAXSTEPS) return false; + if (opcode > ScriptOp.OP_16 && ++nOpCount > MAXSTEPS) return VMState.FAULT; if (opcode >= ScriptOp.OP_PUSHBYTES1 && opcode <= ScriptOp.OP_PUSHBYTES75) { Stack.Push(opReader.ReadBytes((byte)opcode)); - return true; + return VMState.NONE; } switch (opcode) { @@ -92,11 +92,11 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) int offset = opReader.ReadInt16() - 3; int offset_new = (int)opReader.BaseStream.Position + offset; if (offset_new < 0 || offset_new > opReader.BaseStream.Length) - return false; + return VMState.FAULT; bool fValue = true; if (opcode > ScriptOp.OP_JMP) { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; fValue = Stack.Pop(); if (opcode == ScriptOp.OP_JMPIFNOT) fValue = !fValue; @@ -110,11 +110,11 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) return ExecuteOp(ScriptOp.OP_JMP, opReader); case ScriptOp.OP_RET: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem result = Stack.Pop(); int position = (int)(BigInteger)Stack.Pop(); if (position < 0 || position > opReader.BaseStream.Length) - return false; + return VMState.FAULT; Stack.Push(result); opReader.BaseStream.Seek(position, SeekOrigin.Begin); } @@ -123,39 +123,39 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) { UInt160 hash = opReader.ReadSerializable(); byte[] script = Blockchain.Default?.GetContract(hash); - if (script == null) return false; - return ExecuteScript(script, false); + if (script == null) return VMState.FAULT; + return ExecuteScript(script, false) ? VMState.NONE : VMState.FAULT; } case ScriptOp.OP_SYSCALL: - if (service == null) return false; - return service.Invoke(opReader.ReadVarString(), this); - case ScriptOp.OP_VERIFY: - if (Stack.Count < 1) return false; + if (service == null) return VMState.FAULT; + return service.Invoke(opReader.ReadVarString(), this) ? VMState.NONE : VMState.FAULT; + case ScriptOp.OP_HALTIFNOT: + if (Stack.Count < 1) return VMState.FAULT; if (Stack.Peek().GetBooleanArray().All(p => p)) Stack.Pop(); else - return false; + return VMState.HALT; break; case ScriptOp.OP_HALT: - return false; + return VMState.HALT; // Stack ops case ScriptOp.OP_TOALTSTACK: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; AltStack.Push(Stack.Pop()); break; case ScriptOp.OP_FROMALTSTACK: - if (AltStack.Count < 1) return false; + if (AltStack.Count < 1) return VMState.FAULT; Stack.Push(AltStack.Pop()); break; case ScriptOp.OP_2DROP: - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; Stack.Pop(); Stack.Pop(); break; case ScriptOp.OP_2DUP: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Peek(); Stack.Push(x2); @@ -165,7 +165,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_3DUP: { - if (Stack.Count < 3) return false; + if (Stack.Count < 3) return VMState.FAULT; StackItem x3 = Stack.Pop(); StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Peek(); @@ -178,7 +178,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_2OVER: { - if (Stack.Count < 4) return false; + if (Stack.Count < 4) return VMState.FAULT; StackItem x4 = Stack.Pop(); StackItem x3 = Stack.Pop(); StackItem x2 = Stack.Pop(); @@ -192,7 +192,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_2ROT: { - if (Stack.Count < 6) return false; + if (Stack.Count < 6) return VMState.FAULT; StackItem x6 = Stack.Pop(); StackItem x5 = Stack.Pop(); StackItem x4 = Stack.Pop(); @@ -209,7 +209,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_2SWAP: { - if (Stack.Count < 4) return false; + if (Stack.Count < 4) return VMState.FAULT; StackItem x4 = Stack.Pop(); StackItem x3 = Stack.Pop(); StackItem x2 = Stack.Pop(); @@ -221,7 +221,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) } break; case ScriptOp.OP_IFDUP: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; if (Stack.Peek()) Stack.Push(Stack.Peek()); break; @@ -229,16 +229,16 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) Stack.Push(Stack.Count); break; case ScriptOp.OP_DROP: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Pop(); break; case ScriptOp.OP_DUP: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Push(Stack.Peek()); break; case ScriptOp.OP_NIP: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); Stack.Pop(); Stack.Push(x2); @@ -246,7 +246,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_OVER: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Peek(); Stack.Push(x2); @@ -255,10 +255,10 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_PICK: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; int n = (int)(BigInteger)Stack.Pop(); - if (n < 0) return false; - if (Stack.Count < n + 1) return false; + if (n < 0) return VMState.FAULT; + if (Stack.Count < n + 1) return VMState.FAULT; StackItem[] buffer = new StackItem[n]; for (int i = 0; i < n; i++) buffer[i] = Stack.Pop(); @@ -270,11 +270,11 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_ROLL: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; int n = (int)(BigInteger)Stack.Pop(); - if (n < 0) return false; - if (n == 0) return true; - if (Stack.Count < n + 1) return false; + if (n < 0) return VMState.FAULT; + if (n == 0) return VMState.NONE; + if (Stack.Count < n + 1) return VMState.FAULT; StackItem[] buffer = new StackItem[n]; for (int i = 0; i < n; i++) buffer[i] = Stack.Pop(); @@ -286,7 +286,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_ROT: { - if (Stack.Count < 3) return false; + if (Stack.Count < 3) return VMState.FAULT; StackItem x3 = Stack.Pop(); StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); @@ -297,7 +297,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_SWAP: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); Stack.Push(x2); @@ -306,7 +306,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_TUCK: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); Stack.Push(x2); @@ -316,12 +316,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_CAT: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); byte[][] b1 = x1.GetBytesArray(); byte[][] b2 = x2.GetBytesArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; byte[][] r = b1.Zip(b2, (p1, p2) => p1.Concat(p2).ToArray()).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -331,11 +331,11 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_SUBSTR: { - if (Stack.Count < 3) return false; + if (Stack.Count < 3) return VMState.FAULT; int count = (int)(BigInteger)Stack.Pop(); - if (count < 0) return false; + if (count < 0) return VMState.FAULT; int index = (int)(BigInteger)Stack.Pop(); - if (index < 0) return false; + if (index < 0) return VMState.FAULT; StackItem x = Stack.Pop(); byte[][] s = x.GetBytesArray(); s = s.Select(p => p.Skip(index).Take(count).ToArray()).ToArray(); @@ -347,9 +347,9 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_LEFT: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; int count = (int)(BigInteger)Stack.Pop(); - if (count < 0) return false; + if (count < 0) return VMState.FAULT; StackItem x = Stack.Pop(); byte[][] s = x.GetBytesArray(); s = s.Select(p => p.Take(count).ToArray()).ToArray(); @@ -361,12 +361,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_RIGHT: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; int count = (int)(BigInteger)Stack.Pop(); - if (count < 0) return false; + if (count < 0) return VMState.FAULT; StackItem x = Stack.Pop(); byte[][] s = x.GetBytesArray(); - if (s.Any(p => p.Length < count)) return false; + if (s.Any(p => p.Length < count)) return VMState.FAULT; s = s.Select(p => p.Skip(p.Length - count).ToArray()).ToArray(); if (x.IsArray) Stack.Push(s); @@ -376,7 +376,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_SIZE: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Peek(); int[] r = x.GetBytesArray().Select(p => p.Length).ToArray(); if (x.IsArray) @@ -389,7 +389,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) // Bitwise logic case ScriptOp.OP_INVERT: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); BigInteger[] r = x.GetIntArray().Select(p => ~p).ToArray(); if (x.IsArray) @@ -400,12 +400,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_AND: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 & p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -415,12 +415,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_OR: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 | p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -430,12 +430,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_XOR: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 ^ p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -445,12 +445,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_EQUAL: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); byte[][] b1 = x1.GetBytesArray(); byte[][] b2 = x2.GetBytesArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; bool[] r = b1.Zip(b2, (p1, p2) => p1.SequenceEqual(p2)).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -462,7 +462,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) // Numeric case ScriptOp.OP_1ADD: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); BigInteger[] r = x.GetIntArray().Select(p => p + BigInteger.One).ToArray(); if (x.IsArray) @@ -473,7 +473,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_1SUB: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); BigInteger[] r = x.GetIntArray().Select(p => p - BigInteger.One).ToArray(); if (x.IsArray) @@ -484,7 +484,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_2MUL: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); BigInteger[] r = x.GetIntArray().Select(p => p << 1).ToArray(); if (x.IsArray) @@ -495,7 +495,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_2DIV: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); BigInteger[] r = x.GetIntArray().Select(p => p >> 1).ToArray(); if (x.IsArray) @@ -506,7 +506,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_NEGATE: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); BigInteger[] r = x.GetIntArray().Select(p => -p).ToArray(); if (x.IsArray) @@ -517,7 +517,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_ABS: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); BigInteger[] r = x.GetIntArray().Select(p => BigInteger.Abs(p)).ToArray(); if (x.IsArray) @@ -528,7 +528,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_NOT: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); bool[] r = x.GetBooleanArray().Select(p => !p).ToArray(); if (x.IsArray) @@ -539,7 +539,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_0NOTEQUAL: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); bool[] r = x.GetIntArray().Select(p => p != BigInteger.Zero).ToArray(); if (x.IsArray) @@ -550,12 +550,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_ADD: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 + p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -565,12 +565,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_SUB: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 - p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -580,12 +580,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_MUL: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 * p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -595,12 +595,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_DIV: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 / p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -610,12 +610,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_MOD: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 % p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -625,12 +625,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_LSHIFT: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 << (int)p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -640,12 +640,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_RSHIFT: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => p1 >> (int)p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -655,12 +655,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_BOOLAND: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); bool[] b1 = x1.GetBooleanArray(); bool[] b2 = x2.GetBooleanArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; bool[] r = b1.Zip(b2, (p1, p2) => p1 && p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -670,12 +670,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_BOOLOR: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); bool[] b1 = x1.GetBooleanArray(); bool[] b2 = x2.GetBooleanArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; bool[] r = b1.Zip(b2, (p1, p2) => p1 || p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -685,12 +685,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_NUMEQUAL: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; bool[] r = b1.Zip(b2, (p1, p2) => p1 == p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -700,12 +700,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_NUMNOTEQUAL: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; bool[] r = b1.Zip(b2, (p1, p2) => p1 != p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -715,12 +715,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_LESSTHAN: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; bool[] r = b1.Zip(b2, (p1, p2) => p1 < p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -730,12 +730,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_GREATERTHAN: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; bool[] r = b1.Zip(b2, (p1, p2) => p1 > p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -745,12 +745,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_LESSTHANOREQUAL: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; bool[] r = b1.Zip(b2, (p1, p2) => p1 <= p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -760,12 +760,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_GREATERTHANOREQUAL: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; bool[] r = b1.Zip(b2, (p1, p2) => p1 >= p2).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -775,12 +775,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_MIN: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => BigInteger.Min(p1, p2)).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -790,12 +790,12 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_MAX: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); BigInteger[] b1 = x1.GetIntArray(); BigInteger[] b2 = x2.GetIntArray(); - if (b1.Length != b2.Length) return false; + if (b1.Length != b2.Length) return VMState.FAULT; BigInteger[] r = b1.Zip(b2, (p1, p2) => BigInteger.Max(p1, p2)).ToArray(); if (x1.IsArray || x2.IsArray) Stack.Push(r); @@ -805,7 +805,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_WITHIN: { - if (Stack.Count < 3) return false; + if (Stack.Count < 3) return VMState.FAULT; BigInteger b = (BigInteger)Stack.Pop(); BigInteger a = (BigInteger)Stack.Pop(); BigInteger x = (BigInteger)Stack.Pop(); @@ -816,7 +816,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) // Crypto case ScriptOp.OP_RIPEMD160: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); byte[][] r = x.GetBytesArray().Select(p => p.RIPEMD160()).ToArray(); if (x.IsArray) @@ -828,7 +828,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) case ScriptOp.OP_SHA1: using (SHA1Managed sha = new SHA1Managed()) { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); byte[][] r = x.GetBytesArray().Select(p => sha.ComputeHash(p)).ToArray(); if (x.IsArray) @@ -839,7 +839,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_SHA256: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); byte[][] r = x.GetBytesArray().Select(p => p.Sha256()).ToArray(); if (x.IsArray) @@ -850,7 +850,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_HASH160: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); byte[][] r = x.GetBytesArray().Select(p => p.Sha256().RIPEMD160()).ToArray(); if (x.IsArray) @@ -861,7 +861,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_HASH256: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem x = Stack.Pop(); byte[][] r = x.GetBytesArray().Select(p => p.Sha256().Sha256()).ToArray(); if (x.IsArray) @@ -872,7 +872,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_CHECKSIG: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; byte[] pubkey = (byte[])Stack.Pop(); byte[] signature = (byte[])Stack.Pop(); Stack.Push(VerifySignature(hash, signature, pubkey)); @@ -880,18 +880,18 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_CHECKMULTISIG: { - if (Stack.Count < 4) return false; + if (Stack.Count < 4) return VMState.FAULT; int n = (int)(BigInteger)Stack.Pop(); - if (n < 1) return false; - if (Stack.Count < n + 2) return false; + if (n < 1) return VMState.FAULT; + if (Stack.Count < n + 2) return VMState.FAULT; nOpCount += n; - if (nOpCount > MAXSTEPS) return false; + if (nOpCount > MAXSTEPS) return VMState.FAULT; byte[][] pubkeys = new byte[n][]; for (int i = 0; i < n; i++) pubkeys[i] = (byte[])Stack.Pop(); int m = (int)(BigInteger)Stack.Pop(); - if (m < 1 || m > n) return false; - if (Stack.Count < m) return false; + if (m < 1 || m > n) return VMState.FAULT; + if (Stack.Count < m) return VMState.FAULT; byte[][] signatures = new byte[m][]; for (int i = 0; i < m; i++) signatures[i] = (byte[])Stack.Pop(); @@ -911,7 +911,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) // Array case ScriptOp.OP_ARRAYSIZE: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem arr = Stack.Pop(); if (arr.IsArray) Stack.Push(arr.Count); @@ -921,45 +921,45 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_PACK: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; int c = (int)(BigInteger)Stack.Pop(); - if (Stack.Count < c) return false; + if (Stack.Count < c) return VMState.FAULT; StackItem[] arr = new StackItem[c]; while (c-- > 0) { arr[c] = Stack.Pop(); - if (arr[c].IsArray) return false; + if (arr[c].IsArray) return VMState.FAULT; } Stack.Push(new StackItem(arr)); } break; case ScriptOp.OP_UNPACK: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem arr = Stack.Pop(); - if (!arr.IsArray) return false; + if (!arr.IsArray) return VMState.FAULT; foreach (StackItem item in arr) Stack.Push(item); Stack.Push(arr.Count); } break; case ScriptOp.OP_DISTINCT: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Push(new StackItem(Stack.Pop().Distinct())); break; case ScriptOp.OP_SORT: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Push(Stack.Pop().GetIntArray().OrderBy(p => p).ToArray()); break; case ScriptOp.OP_REVERSE: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Push(new StackItem(Stack.Pop().Reverse())); break; case ScriptOp.OP_CONCAT: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; int c = (int)(BigInteger)Stack.Pop(); - if (Stack.Count < c) return false; + if (Stack.Count < c) return VMState.FAULT; IEnumerable items = Enumerable.Empty(); while (c-- > 0) items = Stack.Pop().Concat(items); @@ -968,9 +968,9 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_UNION: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; int c = (int)(BigInteger)Stack.Pop(); - if (Stack.Count < c) return false; + if (Stack.Count < c) return VMState.FAULT; IEnumerable items = Enumerable.Empty(); while (c-- > 0) items = Stack.Pop().Union(items); @@ -979,9 +979,9 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_INTERSECT: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; int c = (int)(BigInteger)Stack.Pop(); - if (Stack.Count < c) return false; + if (Stack.Count < c) return VMState.FAULT; IEnumerable items = Enumerable.Empty(); while (c-- > 0) items = Stack.Pop().Intersect(items); @@ -990,7 +990,7 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_EXCEPT: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; StackItem x2 = Stack.Pop(); StackItem x1 = Stack.Pop(); Stack.Push(new StackItem(x1.Except(x2))); @@ -998,21 +998,21 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) break; case ScriptOp.OP_TAKE: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; int count = (int)(BigInteger)Stack.Pop(); Stack.Push(new StackItem(Stack.Pop().Take(count))); } break; case ScriptOp.OP_SKIP: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; int count = (int)(BigInteger)Stack.Pop(); Stack.Push(new StackItem(Stack.Pop().Skip(count))); } break; case ScriptOp.OP_PICKITEM: { - if (Stack.Count < 2) return false; + if (Stack.Count < 2) return VMState.FAULT; int index = (int)(BigInteger)Stack.Pop(); StackItem arr = Stack.Pop(); if (arr.Count <= index) @@ -1022,38 +1022,38 @@ private bool ExecuteOp(ScriptOp opcode, BinaryReader opReader) } break; case ScriptOp.OP_ALL: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Push(Stack.Pop().All(p => p)); break; case ScriptOp.OP_ANY: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Push(Stack.Pop().Any(p => p)); break; case ScriptOp.OP_SUM: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Push(Stack.Pop().Aggregate(BigInteger.Zero, (s, p) => s + (BigInteger)p)); break; case ScriptOp.OP_AVERAGE: { - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; StackItem arr = Stack.Pop(); - if (arr.Count == 0) return false; + if (arr.Count == 0) return VMState.FAULT; Stack.Push(arr.Aggregate(BigInteger.Zero, (s, p) => s + (BigInteger)p, p => p / arr.Count)); } break; case ScriptOp.OP_MAXITEM: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Push(Stack.Pop().GetIntArray().Max()); break; case ScriptOp.OP_MINITEM: - if (Stack.Count < 1) return false; + if (Stack.Count < 1) return VMState.FAULT; Stack.Push(Stack.Pop().GetIntArray().Min()); break; default: - return false; + return VMState.FAULT; } - return true; + return VMState.NONE; } private bool ExecuteScript(byte[] script, bool push_only) @@ -1067,7 +1067,9 @@ private bool ExecuteScript(byte[] script, bool push_only) { ScriptOp opcode = (ScriptOp)opReader.ReadByte(); if (push_only && opcode > ScriptOp.OP_16) return false; - if (!ExecuteOp(opcode, opReader)) return false; + VMState state = ExecuteOp(opcode, opReader); + if (state.HasFlag(VMState.FAULT)) return false; + if (state.HasFlag(VMState.HALT)) return true; } } catch (Exception ex) when (ex is EndOfStreamException || ex is FormatException || ex is InvalidCastException) diff --git a/AntSharesCore/Core/Scripts/ScriptOp.cs b/AntSharesCore/Core/Scripts/ScriptOp.cs index 396571c0b1..8e8b9da0ce 100644 --- a/AntSharesCore/Core/Scripts/ScriptOp.cs +++ b/AntSharesCore/Core/Scripts/ScriptOp.cs @@ -40,8 +40,8 @@ public enum ScriptOp : byte OP_RET = 0x66, OP_APPCALL = 0x67, OP_SYSCALL = 0x68, - OP_VERIFY = 0x69, // Marks transaction as invalid if top stack value is not true. True is removed, but false is not. - OP_HALT = 0x6A, // Marks transaction as invalid. + OP_HALTIFNOT = 0x69, + OP_HALT = 0x6A, // Stack diff --git a/AntSharesCore/Core/Scripts/VMState.cs b/AntSharesCore/Core/Scripts/VMState.cs new file mode 100644 index 0000000000..fc4bf38296 --- /dev/null +++ b/AntSharesCore/Core/Scripts/VMState.cs @@ -0,0 +1,12 @@ +using System; + +namespace AntShares.Core.Scripts +{ + [Flags] + internal enum VMState : byte + { + NONE = 0, + HALT = 1 << 0, + FAULT = 1 << 1 + } +} diff --git a/AntSharesDaemon/Shell/MainService.cs b/AntSharesDaemon/Shell/MainService.cs index 4b9bf9070a..a2705a921f 100644 --- a/AntSharesDaemon/Shell/MainService.cs +++ b/AntSharesDaemon/Shell/MainService.cs @@ -135,7 +135,7 @@ private bool OnHelpCommand(string[] args) "\tlist address\n" + "\tlist asset\n" + "\tcreate address [n=1]\n" + - "\timport key \n" + + "\timport key \n" + "\tsend
[fee=0]\n" + "Node Commands:\n" + "\tshow state\n" + @@ -164,10 +164,36 @@ private bool OnImportKeyCommand(string[] args) Console.WriteLine("error"); return true; } - Account account = Program.Wallet.Import(args[2]); - Contract contract = Program.Wallet.GetContracts(account.PublicKeyHash).First(p => p.IsStandard); - Console.WriteLine($"address: {contract.Address}"); - Console.WriteLine($" pubkey: {account.PublicKey.EncodePoint(true).ToHexString()}"); + byte[] prikey = null; + try + { + prikey = Wallet.GetPrivateKeyFromWIF(args[2]); + } + catch (FormatException) { } + if (prikey == null) + { + string[] lines = File.ReadAllLines(args[2]); + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].Length == 64) + prikey = lines[i].HexToBytes(); + else + prikey = Wallet.GetPrivateKeyFromWIF(lines[i]); + Program.Wallet.CreateAccount(prikey); + Array.Clear(prikey, 0, prikey.Length); + Console.SetCursorPosition(0, Console.CursorTop); + Console.Write($"[{i + 1}/{lines.Length}]"); + } + Console.WriteLine(); + } + else + { + Account account = Program.Wallet.CreateAccount(prikey); + Array.Clear(prikey, 0, prikey.Length); + Contract contract = Program.Wallet.GetContracts(account.PublicKeyHash).First(p => p.IsStandard); + Console.WriteLine($"address: {contract.Address}"); + Console.WriteLine($" pubkey: {account.PublicKey.EncodePoint(true).ToHexString()}"); + } return true; } diff --git a/AntSharesUI/UI/ClaimForm.Designer.cs b/AntSharesUI/UI/ClaimForm.Designer.cs index e930558c82..771eda790c 100644 --- a/AntSharesUI/UI/ClaimForm.Designer.cs +++ b/AntSharesUI/UI/ClaimForm.Designer.cs @@ -79,6 +79,7 @@ private void InitializeComponent() this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.MaximizeBox = false; this.Name = "ClaimForm"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ClaimForm_FormClosing); this.Load += new System.EventHandler(this.ClaimForm_Load); this.ResumeLayout(false); this.PerformLayout(); diff --git a/AntSharesUI/UI/ClaimForm.cs b/AntSharesUI/UI/ClaimForm.cs index 729d1cdd8e..49f19e13bb 100644 --- a/AntSharesUI/UI/ClaimForm.cs +++ b/AntSharesUI/UI/ClaimForm.cs @@ -13,13 +13,35 @@ public ClaimForm() InitializeComponent(); } + private void CalculateClaimAmountUnavailable(uint height) + { + textBox2.Text = Wallet.CalculateClaimAmountUnavailable(Program.CurrentWallet.FindUnspentCoins().Where(p => p.AssetId.Equals(Blockchain.AntShare.Hash)).Select(p => p.Input), height).ToString(); + } + private void ClaimForm_Load(object sender, EventArgs e) { Fixed8 amount_available = Wallet.CalculateClaimAmount(Program.CurrentWallet.GetUnclaimedCoins().Select(p => p.Input)); - Fixed8 amount_unavailable = Wallet.CalculateClaimAmountUnavailable(Program.CurrentWallet.FindUnspentCoins().Where(p => p.AssetId.Equals(Blockchain.AntShare.Hash)).Select(p => p.Input), Blockchain.Default.Height); textBox1.Text = amount_available.ToString(); - textBox2.Text = amount_unavailable.ToString(); if (amount_available == Fixed8.Zero) button1.Enabled = false; + CalculateClaimAmountUnavailable(Blockchain.Default.Height); + Blockchain.PersistCompleted += Blockchain_PersistCompleted; + } + + private void ClaimForm_FormClosing(object sender, FormClosingEventArgs e) + { + Blockchain.PersistCompleted -= Blockchain_PersistCompleted; + } + + private void Blockchain_PersistCompleted(object sender, Block block) + { + if (InvokeRequired) + { + BeginInvoke(new Action(Blockchain_PersistCompleted), sender, block); + } + else + { + CalculateClaimAmountUnavailable(block.Height); + } } private void button1_Click(object sender, EventArgs e)