mirror of https://github.com/Qortal/AT
Browse Source
Conversion to big-endian to allow reuse of hash output without having to swap endian. e.g. saving output of HASH160 into data segment, and then hashing more of data segment to produce P2SH address. Also changed hashing functions to fetch data start address and data byte length from data segment, rather than loading values into A. Tidied up some tests. Remove obsolete ACCT test.master
catbref
5 years ago
13 changed files with 230 additions and 458 deletions
@ -1,221 +0,0 @@
|
||||
import static common.TestUtils.hexToBytes; |
||||
import static org.junit.Assert.*; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
import java.nio.ByteOrder; |
||||
import java.security.MessageDigest; |
||||
import java.security.NoSuchAlgorithmException; |
||||
import java.security.SecureRandom; |
||||
import java.security.Security; |
||||
import java.util.Arrays; |
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider; |
||||
import org.ciyam.at.ExecutionException; |
||||
import org.ciyam.at.FunctionCode; |
||||
import org.ciyam.at.MachineState; |
||||
import org.ciyam.at.OpCode; |
||||
import org.junit.After; |
||||
import org.junit.Before; |
||||
import org.junit.BeforeClass; |
||||
import org.junit.Test; |
||||
|
||||
import common.ACCTAPI; |
||||
import common.TestLogger; |
||||
|
||||
public class TestACCT { |
||||
|
||||
public TestLogger logger; |
||||
public ACCTAPI api; |
||||
public MachineState state; |
||||
public ByteBuffer codeByteBuffer; |
||||
public ByteBuffer dataByteBuffer; |
||||
|
||||
@BeforeClass |
||||
public static void beforeClass() { |
||||
Security.insertProviderAt(new BouncyCastleProvider(), 0); |
||||
} |
||||
|
||||
@Before |
||||
public void beforeTest() { |
||||
logger = new TestLogger(); |
||||
api = new ACCTAPI(); |
||||
codeByteBuffer = ByteBuffer.allocate(0x0200 * 1).order(ByteOrder.LITTLE_ENDIAN); |
||||
dataByteBuffer = ByteBuffer.allocate(0x0020 * 8).order(ByteOrder.LITTLE_ENDIAN); |
||||
} |
||||
|
||||
@After |
||||
public void afterTest() { |
||||
dataByteBuffer = null; |
||||
codeByteBuffer = null; |
||||
api = null; |
||||
logger = null; |
||||
} |
||||
|
||||
private byte[] simulate() { |
||||
// version 0002, reserved 0000, code 0200 * 1, data 0020 * 8, call stack 0010 * 4, user stack 0010 * 4, minActivation = 0
|
||||
byte[] headerBytes = hexToBytes("0200" + "0000" + "0002" + "2000" + "1000" + "1000" + "0000000000000000"); |
||||
byte[] codeBytes = codeByteBuffer.array(); |
||||
byte[] dataBytes = dataByteBuffer.array(); |
||||
|
||||
state = new MachineState(api, logger, headerBytes, codeBytes, dataBytes); |
||||
|
||||
return executeAndCheck(state); |
||||
} |
||||
|
||||
private byte[] continueSimulation(byte[] savedState) { |
||||
byte[] codeBytes = codeByteBuffer.array(); |
||||
state = MachineState.fromBytes(api, logger, savedState, codeBytes); |
||||
|
||||
return executeAndCheck(state); |
||||
} |
||||
|
||||
private byte[] executeAndCheck(MachineState state) { |
||||
state.execute(); |
||||
|
||||
api.setCurrentBalance(state.getCurrentBalance()); |
||||
|
||||
byte[] stateBytes = state.toBytes(); |
||||
byte[] codeBytes = state.getCodeBytes(); |
||||
MachineState restoredState = MachineState.fromBytes(api, logger, stateBytes, codeBytes); |
||||
byte[] restoredStateBytes = restoredState.toBytes(); |
||||
byte[] restoredCodeBytes = state.getCodeBytes(); |
||||
|
||||
assertTrue("Serialization->Deserialization->Reserialization error", Arrays.equals(stateBytes, restoredStateBytes)); |
||||
assertTrue("Serialization->Deserialization->Reserialization error", Arrays.equals(codeBytes, restoredCodeBytes)); |
||||
|
||||
return stateBytes; |
||||
} |
||||
|
||||
@Test |
||||
public void testACCT() throws ExecutionException { |
||||
// DATA
|
||||
final int addrHashPart1 = 0x0; |
||||
final int addrHashPart2 = 0x1; |
||||
final int addrHashPart3 = 0x2; |
||||
final int addrHashPart4 = 0x3; |
||||
final int addrAddressPart1 = 0x4; |
||||
final int addrAddressPart2 = 0x5; |
||||
final int addrAddressPart3 = 0x6; |
||||
final int addrAddressPart4 = 0x7; |
||||
final int addrRefundMinutes = 0x8; |
||||
final int addrRefundTimestamp = 0x9; |
||||
final int addrLastTimestamp = 0xa; |
||||
final int addrBlockTimestamp = 0xb; |
||||
final int addrTxType = 0xc; |
||||
final int addrComparator = 0xd; |
||||
final int addrAddressTemp1 = 0xe; |
||||
final int addrAddressTemp2 = 0xf; |
||||
final int addrAddressTemp3 = 0x10; |
||||
final int addrAddressTemp4 = 0x11; |
||||
|
||||
byte[] secret = new byte[32]; |
||||
new SecureRandom().nextBytes(secret); |
||||
|
||||
try { |
||||
MessageDigest digester = MessageDigest.getInstance("SHA-256"); |
||||
byte[] digest = digester.digest(secret); |
||||
|
||||
dataByteBuffer.put(digest); |
||||
} catch (NoSuchAlgorithmException e) { |
||||
throw new ExecutionException("No SHA-256 message digest service available", e); |
||||
} |
||||
|
||||
// Destination address (based on "R" for "Responder", where "R" is 0x52)
|
||||
dataByteBuffer.put(hexToBytes("5200000000000000520000000000000052000000000000005200000000000000")); |
||||
|
||||
// Expiry in minutes (but actually blocks in this test case)
|
||||
dataByteBuffer.putLong(8L); |
||||
|
||||
// Code labels
|
||||
final int addrTxLoop = 0x36; |
||||
final int addrCheckTx = 0x4b; |
||||
final int addrCheckSender = 0x64; |
||||
final int addrCheckMessage = 0xab; |
||||
final int addrPayout = 0xdf; |
||||
final int addrRefund = 0x102; |
||||
|
||||
int tempPC; |
||||
|
||||
// init:
|
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_CREATION_TIMESTAMP.value).putInt(addrRefundTimestamp); |
||||
codeByteBuffer.put(OpCode.SET_DAT.value).putInt(addrLastTimestamp).putInt(addrRefundTimestamp); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET_DAT_2.value).putShort(FunctionCode.ADD_MINUTES_TO_TIMESTAMP.value).putInt(addrRefundTimestamp) |
||||
.putInt(addrRefundTimestamp).putInt(addrRefundMinutes); |
||||
codeByteBuffer.put(OpCode.SET_PCS.value); |
||||
|
||||
// loop:
|
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_BLOCK_TIMESTAMP.value).putInt(addrBlockTimestamp); |
||||
tempPC = codeByteBuffer.position(); |
||||
codeByteBuffer.put(OpCode.BLT_DAT.value).putInt(addrBlockTimestamp).putInt(addrRefundTimestamp).put((byte) (addrTxLoop - tempPC)); |
||||
codeByteBuffer.put(OpCode.JMP_ADR.value).putInt(addrRefund); |
||||
|
||||
// txloop:
|
||||
assertEquals(addrTxLoop, codeByteBuffer.position()); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.PUT_TX_AFTER_TIMESTAMP_IN_A.value).putInt(addrLastTimestamp); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.CHECK_A_IS_ZERO.value).putInt(addrComparator); |
||||
tempPC = codeByteBuffer.position(); |
||||
codeByteBuffer.put(OpCode.BZR_DAT.value).putInt(addrComparator).put((byte) (addrCheckTx - tempPC)); |
||||
codeByteBuffer.put(OpCode.STP_IMD.value); |
||||
|
||||
// checkTx:
|
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_TIMESTAMP_FROM_TX_IN_A.value).putInt(addrLastTimestamp); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_TYPE_FROM_TX_IN_A.value).putInt(addrTxType); |
||||
tempPC = codeByteBuffer.position(); |
||||
codeByteBuffer.put(OpCode.BNZ_DAT.value).putInt(addrTxType).put((byte) (addrCheckSender - tempPC)); |
||||
codeByteBuffer.put(OpCode.JMP_ADR.value).putInt(addrTxLoop); |
||||
|
||||
// checkSender
|
||||
assertEquals(addrCheckSender, codeByteBuffer.position()); |
||||
codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PUT_ADDRESS_FROM_TX_IN_A_INTO_B.value); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_B1.value).putInt(addrAddressTemp1); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_B2.value).putInt(addrAddressTemp2); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_B3.value).putInt(addrAddressTemp3); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.GET_B4.value).putInt(addrAddressTemp4); |
||||
tempPC = codeByteBuffer.position(); |
||||
codeByteBuffer.put(OpCode.BNE_DAT.value).putInt(addrAddressTemp1).putInt(addrAddressPart1).put((byte) (addrTxLoop - tempPC)); |
||||
tempPC = codeByteBuffer.position(); |
||||
codeByteBuffer.put(OpCode.BNE_DAT.value).putInt(addrAddressTemp2).putInt(addrAddressPart2).put((byte) (addrTxLoop - tempPC)); |
||||
tempPC = codeByteBuffer.position(); |
||||
codeByteBuffer.put(OpCode.BNE_DAT.value).putInt(addrAddressTemp3).putInt(addrAddressPart3).put((byte) (addrTxLoop - tempPC)); |
||||
tempPC = codeByteBuffer.position(); |
||||
codeByteBuffer.put(OpCode.BNE_DAT.value).putInt(addrAddressTemp4).putInt(addrAddressPart4).put((byte) (addrTxLoop - tempPC)); |
||||
|
||||
// checkMessage:
|
||||
assertEquals(addrCheckMessage, codeByteBuffer.position()); |
||||
codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PUT_MESSAGE_FROM_TX_IN_A_INTO_B.value); |
||||
codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.SWAP_A_AND_B.value); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B1.value).putInt(addrHashPart1); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B2.value).putInt(addrHashPart2); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B3.value).putInt(addrHashPart3); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B4.value).putInt(addrHashPart4); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_RET.value).putShort(FunctionCode.CHECK_SHA256_A_WITH_B.value).putInt(addrComparator); |
||||
tempPC = codeByteBuffer.position(); |
||||
codeByteBuffer.put(OpCode.BNZ_DAT.value).putInt(addrComparator).put((byte) (addrPayout - tempPC)); |
||||
codeByteBuffer.put(OpCode.JMP_ADR.value).putInt(addrTxLoop); |
||||
|
||||
// payout:
|
||||
assertEquals(addrPayout, codeByteBuffer.position()); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B1.value).putInt(addrAddressPart1); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B2.value).putInt(addrAddressPart2); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B3.value).putInt(addrAddressPart3); |
||||
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.SET_B4.value).putInt(addrAddressPart4); |
||||
codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.MESSAGE_A_TO_ADDRESS_IN_B.value); |
||||
codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PAY_ALL_TO_ADDRESS_IN_B.value); |
||||
codeByteBuffer.put(OpCode.FIN_IMD.value); |
||||
|
||||
// refund:
|
||||
assertEquals(addrRefund, codeByteBuffer.position()); |
||||
codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PUT_CREATOR_INTO_B.value); |
||||
codeByteBuffer.put(OpCode.EXT_FUN.value).putShort(FunctionCode.PAY_ALL_TO_ADDRESS_IN_B.value); |
||||
codeByteBuffer.put(OpCode.FIN_IMD.value); |
||||
|
||||
byte[] savedState = simulate(); |
||||
|
||||
while (!state.getIsFinished()) { |
||||
((ACCTAPI) state.getAPI()).generateNextBlock(secret); |
||||
|
||||
savedState = continueSimulation(savedState); |
||||
} |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue