package com.yoghurt.crypto.transactions.client.util.script; import java.util.Deque; import java.util.Iterator; import com.googlecode.gwt.crypto.bouncycastle.util.Arrays; import com.yoghurt.crypto.transactions.client.util.transaction.ComputeUtil; import com.yoghurt.crypto.transactions.shared.domain.StackObject; import com.yoghurt.crypto.transactions.shared.util.ScriptOperationUtil; public final class ScriptExecutionUtil { private static final byte[] FALSE = new byte[] { }; private static final byte[] TRUE = new byte[] { 0x01 }; private ScriptExecutionUtil() {} public static void execute(final ExecutionStep step) { final Deque<StackObject> stack = step.getStack(); if(ScriptOperationUtil.isDataPushOperation(step.getInstruction().getOperation())) { addStackObject(stack, step.getInstruction().getBytes()); } switch(step.getInstruction().getOperation()) { case OP_DUP: addStackObject(stack, stack.peek()); break; case OP_2DUP: final Iterator<StackObject> dup2Iterator = stack.iterator(); addStackObject(stack, dup2Iterator.next()); addStackObject(stack, dup2Iterator.next()); break; case OP_3DUP: final Iterator<StackObject> dup3Iterator = stack.iterator(); addStackObject(stack, dup3Iterator.next()); addStackObject(stack, dup3Iterator.next()); addStackObject(stack, dup3Iterator.next()); break; case OP_DROP: stack.remove(); break; case OP_2DROP: stack.remove(); stack.remove(); break; case OP_CHECKSIG: stack.remove(); stack.remove(); // TODO Do actual checksig addTrue(stack); break; case OP_EQUAL: final StackObject objEqualA = stack.poll(); final StackObject objEqualB = stack.poll(); if(Arrays.areEqual(objEqualA.getBytes(), objEqualB.getBytes())) { addTrue(stack); } else { addFalse(stack); } break; case OP_EQUALVERIFY: final StackObject objEqualVerifyA = stack.poll(); final StackObject objEqualVerifyB = stack.poll(); if(!Arrays.areEqual(objEqualVerifyA.getBytes(), objEqualVerifyB.getBytes())) { addException(step); } break; case OP_HASH160: final StackObject poll = stack.poll(); final byte[] hash160 = ComputeUtil.computeHash160(poll.getBytes()); addStackObject(stack, hash160); break; case OP_TRUE: addTrue(stack); break; case OP_FALSE: addFalse(stack); break; case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_10: case OP_11: case OP_12: case OP_13: case OP_14: case OP_15: case OP_16: addStackObject(stack, step.getInstruction().getOperation().getOpcode() - 80); break; default: } } private static void addException(final ExecutionStep step) { step.setExecutionError(true); } private static void addTrue(final Deque<StackObject> stack) { addStackObject(stack, TRUE); } private static void addFalse(final Deque<StackObject> stack) { addStackObject(stack, FALSE); } private static void addStackObject(final Deque<StackObject> stack, final int value) { addStackObject(stack, new StackObject(new byte[] { (byte) value })); } private static void addStackObject(final Deque<StackObject> stack, final byte[] bytes) { addStackObject(stack, new StackObject(bytes)); } private static void addStackObject(final Deque<StackObject> stack, final StackObject object) { stack.addFirst(object); } }