public ScriptBuilder EmitJump(EVMOpCode op, short offset) { if (op != EVMOpCode.JMP && op != EVMOpCode.JMPIF && op != EVMOpCode.JMPIFNOT && op != EVMOpCode.CALL) { throw new ArgumentException(); } return(Emit(op, BitConverter.GetBytes(offset))); }
/// <summary> /// Create new instruction /// </summary> /// <param name="location">Location</param> /// <param name="opCode">Opcode</param> public Instruction New(InstructionLocation location, EVMOpCode opCode) { var ret = (Instruction)Activator.CreateInstance(InstructionType); ret.Location = location; ret.OpCode = opCode; return(ret); }
public ScriptBuilder Emit(EVMOpCode op, params byte[] arg) { writer.WriteByte((byte)op); if (arg != null) { writer.Write(arg, 0, arg.Length); } return(this); }
/// <summary> /// Parse script to instructions /// </summary> /// <param name="script">Script</param> public IEnumerable <Instruction> Parse(byte[] script) { var index = 0; var offset = 0L; var opType = typeof(EVMOpCode); using (var ms = new MemoryStream(script)) using (var reader = new BinaryReader(ms)) { while (offset < ms.Length) { var location = new InstructionLocation() { Index = index, Offset = offset }; var opRead = reader.ReadByte(); if (!Enum.IsDefined(opType, opRead)) { yield break; } EVMOpCode opcode = (EVMOpCode)Enum.ToObject(opType, opRead); if (!_cache.TryGetValue(opcode, out var attr)) { yield break; } Instruction i = attr.New(location, opcode); if (!attr.Fill(reader, i)) { yield break; } offset = ms.Position; index++; yield return(i); } } }
/// <summary> /// Check operand with one BigIntegers /// </summary> /// <param name="operand">Operand</param> /// <param name="check">Check</param> protected void InternalTestBigInteger(EVMOpCode operand, Func <BigInteger, object> check) { // Test without push using (var script = new ScriptBuilder(operand)) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Test with wrong type using (var script = new ScriptBuilder ( EVMOpCode.PUSH1, EVMOpCode.NEWARRAY, operand )) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Test with push foreach (var bi in IntSingleIteration()) { using (var script = new ScriptBuilder()) using (var engine = CreateEngine(Args)) { // Make the script script.EmitPush(bi); script.Emit(operand, EVMOpCode.RET); // Load script engine.LoadScript(script); // Execute var currentContext = engine.CurrentContext; { // PUSH A engine.StepInto(); Assert.AreEqual(1, currentContext.EvaluationStack.Count); } // Operand engine.StepInto(2); try { var ret = check(bi); using (var it = engine.ResultStack.Pop()) { CheckValue(it, ret); } // RET Assert.AreEqual(EVMState.Halt, engine.State); CheckClean(engine); } catch { // RET Assert.AreEqual(EVMState.Fault, engine.State); CheckClean(engine, false); } } } }
/// <summary> /// Check operand with two BigIntegers /// </summary> /// <param name="operand">Operand</param> /// <param name="check">Check</param> protected void InternalTestBigInteger(EVMOpCode operand, Func <BigIntegerPair, object> check) { // Test without push using (var script = new ScriptBuilder(operand)) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Test with wrong type using (var script = new ScriptBuilder ( EVMOpCode.PUSH1, EVMOpCode.PUSH1, EVMOpCode.NEWARRAY, operand )) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute if (operand == EVMOpCode.EQUAL) { // Equal command don't FAULT here Assert.IsTrue(engine.Execute()); using (var i = engine.ResultStack.Pop <BooleanStackItem>()) { Assert.AreEqual(i.Value, false); } } else { Assert.IsFalse(engine.Execute()); } // Check CheckClean(engine, false); } // Test with push foreach (var pair in IntPairIteration()) { using (var script = new ScriptBuilder()) using (var engine = CreateEngine(Args)) { // Make the script foreach (var bb in new BigInteger[] { pair.A, pair.B }) { script.EmitPush(bb); } script.Emit(operand, EVMOpCode.RET); // Load script engine.LoadScript(script.ToArray()); // Execute var currentContext = engine.CurrentContext; { // PUSH A engine.StepInto(); Assert.AreEqual(1, currentContext.EvaluationStack.Count); // PUSH B engine.StepInto(); Assert.AreEqual(2, currentContext.EvaluationStack.Count); } // Operand engine.StepInto(); engine.StepInto(); try { var ret = check(pair); using (var it = engine.ResultStack.Pop()) { CheckValue(it, ret); } // RET Assert.AreEqual(EVMState.Halt, engine.State); CheckClean(engine); } catch { // RET Assert.AreEqual(EVMState.Fault, engine.State); CheckClean(engine, false); } } } // Test with dup foreach (var i in IntSingleIteration()) { using (var script = new ScriptBuilder()) using (var engine = CreateEngine(Args)) { // Make the script script.EmitPush(i); script.Emit(EVMOpCode.DUP); script.Emit(operand, EVMOpCode.RET); // Load script engine.LoadScript(script.ToArray()); // Execute var currentContext = engine.CurrentContext; { // PUSH A engine.StepInto(); Assert.AreEqual(1, currentContext.EvaluationStack.Count); // PUSH B engine.StepInto(); Assert.AreEqual(2, currentContext.EvaluationStack.Count); } // Operand engine.StepInto(2); try { var ret = check(new BigIntegerPair(i, i)); using (var it = engine.ResultStack.Pop()) { CheckValue(it, ret); } // RET Assert.AreEqual(EVMState.Halt, engine.State); CheckClean(engine); } catch { // RET Assert.AreEqual(EVMState.Fault, engine.State); CheckClean(engine, false); } } } }
/// <summary> /// Check operand with one BigIntegers /// </summary> /// <param name="operand">Operand</param> /// <param name="check">Check</param> protected void InternalTestBigInteger(EVMOpCode operand, Action <IExecutionEngine, BigInteger, CancelEventArgs> check) { // Test without push using (var script = new ScriptBuilder(operand)) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Test with wrong type using (var script = new ScriptBuilder ( EVMOpCode.PUSH1, EVMOpCode.NEWARRAY, operand )) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Test with push Stopwatch sw = new Stopwatch(); foreach (var bi in IntSingleIteration()) { using (var script = new ScriptBuilder()) using (var engine = CreateEngine(Args)) { // Make the script script.EmitPush(bi); script.Emit(operand, EVMOpCode.RET); // Load script engine.LoadScript(script); // Execute using (var currentContext = engine.CurrentContext) { // PUSH A engine.StepInto(); Assert.AreEqual(1, currentContext.EvaluationStack.Count); } // Operand CancelEventArgs cancel = new CancelEventArgs(false); #pragma warning disable CS0162 if (CalculateNumericalTimes) { sw.Restart(); } #pragma warning restore engine.StepInto(2); check(engine, bi, cancel); #pragma warning disable CS0162 if (CalculateNumericalTimes) { sw.Stop(); Console.WriteLine("[" + sw.Elapsed.ToString() + "] " + bi); } #pragma warning restore if (cancel.Cancel) { continue; } // RET engine.StepInto(); Assert.AreEqual(EVMState.Halt, engine.State); // Check CheckClean(engine); } } }
/// <summary> /// Check operand with two BigIntegers /// </summary> /// <param name="operand">Operand</param> /// <param name="check">Check</param> protected void InternalTestBigInteger(EVMOpCode operand, Action <IExecutionEngine, BigInteger, BigInteger, CancelEventArgs> check) { // Test without push using (var script = new ScriptBuilder(operand)) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Test with wrong type using (var script = new ScriptBuilder ( EVMOpCode.PUSH1, EVMOpCode.PUSH1, EVMOpCode.NEWARRAY, operand )) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute if (operand == EVMOpCode.EQUAL) { // Equal command don't FAULT here Assert.IsTrue(engine.Execute()); Assert.AreEqual(engine.ResultStack.Pop <BooleanStackItem>().Value, false); } else { Assert.IsFalse(engine.Execute()); } // Check CheckClean(engine, false); } Stopwatch sw = new Stopwatch(); // Test with push foreach (var pair in IntPairIteration()) { using (var script = new ScriptBuilder()) using (var engine = CreateEngine(Args)) { // Make the script foreach (BigInteger bb in new BigInteger[] { pair.A, pair.B }) { script.EmitPush(bb); } script.Emit(operand, EVMOpCode.RET); // Load script engine.LoadScript(script.ToArray()); // Execute using (var currentContext = engine.CurrentContext) { // PUSH A engine.StepInto(); Assert.AreEqual(1, currentContext.EvaluationStack.Count); // PUSH B engine.StepInto(); Assert.AreEqual(2, currentContext.EvaluationStack.Count); } // Operand CancelEventArgs cancel = new CancelEventArgs(false); #pragma warning disable CS0162 if (CalculateNumericalTimes) { sw.Restart(); } #pragma warning restore engine.StepInto(); engine.StepInto(); check(engine, pair.A, pair.B, cancel); #pragma warning disable CS0162 if (CalculateNumericalTimes) { sw.Stop(); Console.WriteLine("[" + sw.Elapsed.ToString() + "] " + pair.A + " " + operand.ToString() + " " + pair.B); } #pragma warning restore if (cancel.Cancel) { CheckClean(engine, false); continue; } // RET Assert.AreEqual(EVMState.Halt, engine.State); // Check CheckClean(engine); } } // Test with dup foreach (var i in IntSingleIteration()) { using (var script = new ScriptBuilder()) using (var engine = CreateEngine(Args)) { // Make the script script.EmitPush(i); script.Emit(EVMOpCode.DUP); script.Emit(operand, EVMOpCode.RET); // Load script engine.LoadScript(script.ToArray()); // Execute using (var currentContext = engine.CurrentContext) { // PUSH A engine.StepInto(); Assert.AreEqual(1, currentContext.EvaluationStack.Count); // PUSH B engine.StepInto(); Assert.AreEqual(2, currentContext.EvaluationStack.Count); } // Operand CancelEventArgs cancel = new CancelEventArgs(false); #pragma warning disable CS0162 if (CalculateNumericalTimes) { sw.Restart(); } #pragma warning restore engine.StepInto(2); check(engine, i, i, cancel); #pragma warning disable CS0162 if (CalculateNumericalTimes) { sw.Stop(); Console.WriteLine("[" + sw.Elapsed.ToString() + "] " + i + " " + operand.ToString() + " " + i); } #pragma warning restore if (cancel.Cancel) { CheckClean(engine, false); continue; } // RET engine.StepInto(); Assert.AreEqual(EVMState.Halt, engine.State); // Check CheckClean(engine); } } }
public void APPCALL_AND_TAILCALL(EVMOpCode opcode) { Assert.IsTrue(opcode == EVMOpCode.APPCALL || opcode == EVMOpCode.TAILCALL); // Check without IScriptTable using (var script = new ScriptBuilder ( new byte[] { (byte)opcode, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A } )) { // Test cache with the real hash byte[] msg = Args.ScriptTable.GetScript(script.ToArray().Skip(1).Take(20).ToArray(), false); byte[] realHash; using (var sha = SHA256.Create()) using (var ripe = new RIPEMD160Managed()) { realHash = sha.ComputeHash(msg); realHash = ripe.ComputeHash(realHash); } script.Emit(opcode); script.Emit(realHash); using (var engine = CreateEngine(new ExecutionEngineArgs())) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Check without complete hash using (var engine = CreateEngine(new ExecutionEngineArgs())) { // Load script engine.LoadScript(script.ToArray().Take((int)script.Length - 1).ToArray()); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Check script using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsTrue(engine.Execute()); // Check Assert.AreEqual(engine.ResultStack.Pop <IntegerStackItem>().Value, 0x04); if (opcode == EVMOpCode.APPCALL) { Assert.AreEqual(engine.ResultStack.Pop <IntegerStackItem>().Value, 0x04); } CheckClean(engine); } } // Check empty hash without push using (var script = new ScriptBuilder ( new byte[] { (byte)opcode, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } )) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Check empty with wrong push using (var script = new ScriptBuilder ( new byte[] { (byte)EVMOpCode.PUSHBYTES1, 0x01, (byte)opcode, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } )) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } // Check empty with with push using (var script = new ScriptBuilder ( new byte[] { (byte)EVMOpCode.PUSHBYTES1 + 19, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, (byte)opcode, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } )) using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute // PUSH engine.StepInto(); Assert.AreEqual(0, engine.CurrentContext.AltStack.Count); Assert.AreEqual(1, engine.CurrentContext.EvaluationStack.Count); Assert.AreEqual(1, engine.InvocationStack.Count); if (opcode == EVMOpCode.APPCALL) { // APP CALL engine.StepInto(); Assert.AreEqual(0, engine.CurrentContext.AltStack.Count); Assert.AreEqual(0, engine.CurrentContext.EvaluationStack.Count); Assert.AreEqual(2, engine.InvocationStack.Count); // PUSH 0x05 engine.StepInto(); Assert.AreEqual(0, engine.CurrentContext.AltStack.Count); Assert.AreEqual(1, engine.CurrentContext.EvaluationStack.Count); Assert.AreEqual(2, engine.InvocationStack.Count); // RET 1 engine.StepInto(); Assert.AreEqual(0, engine.CurrentContext.AltStack.Count); Assert.AreEqual(1, engine.CurrentContext.EvaluationStack.Count); Assert.AreEqual(1, engine.InvocationStack.Count); // RET 2 engine.StepInto(); Assert.AreEqual(1, engine.ResultStack.Count); Assert.AreEqual(0, engine.InvocationStack.Count); } else { // TAIL CALL engine.StepInto(); Assert.AreEqual(0, engine.CurrentContext.AltStack.Count); Assert.AreEqual(0, engine.CurrentContext.EvaluationStack.Count); Assert.AreEqual(1, engine.InvocationStack.Count); // PUSH 0x05 engine.StepInto(); Assert.AreEqual(0, engine.CurrentContext.AltStack.Count); Assert.AreEqual(1, engine.CurrentContext.EvaluationStack.Count); Assert.AreEqual(1, engine.InvocationStack.Count); // RET 1 engine.StepInto(); Assert.AreEqual(1, engine.ResultStack.Count); Assert.AreEqual(0, engine.InvocationStack.Count); } Assert.AreEqual(EVMState.Halt, engine.State); // Check Assert.AreEqual(engine.ResultStack.Pop <IntegerStackItem>().Value, 0x06); CheckClean(engine); } }
void GLOBAL_CALL_EX(EVMOpCode opcode) { // Without push using (var script = new ScriptBuilder ( new byte[] { (byte)opcode, 0x00, 0x01 } )) { using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } } // Without pcount using (var script = new ScriptBuilder ( new byte[] { (byte)opcode, 0x00 } )) { using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } } // Without rvcount using (var script = new ScriptBuilder ( new byte[] { (byte)opcode } )) { using (var engine = CreateEngine(Args)) { // Load script engine.LoadScript(script); // Execute Assert.IsFalse(engine.Execute()); // Check CheckClean(engine, false); } } }
/// <summary> /// Constructor /// </summary> /// <param name="opcode">OpCode</param> /// <param name="rawOpCodes">Raw OpCodes</param> public ScriptBuilder(EVMOpCode opcode, params byte[] rawOpCodes) : this() { Emit(opcode); Emit(rawOpCodes); }