mirror of
https://github.com/Qortal/AT.git
synced 2025-01-30 02:42:14 +00:00
Added support for execution steps/fees.
Two new API calls: getOpCodeSteps(OpCode) : int getFeePerStep() : long This allows API to determine cost per "step" and charge more for (say) function opcodes. MachineState knows the balance at the end of each execution round, so now AT's previousBalance is managed by MachineState and added to serialized data. API calls payCurrentBalanceToB and payPreviousBalanceToB are absorbed into payAmountToB, and amounts passed are calculated by FunctionCode instead. Added API call onFinished(long amount, MachineState state) for when AT has finished so API can return remaining funds (amount) to creator. Added API call isFirstOpCodeAfterSleeping() : boolean to replace dodgy test of state.getSteps() == 0 in getRandomUsingTransactionInA(). The API call getCurrentBalance is now used by MachineState to find out AT's balance at the beginning of execution round. After this, MachineState manages the balance until the end of execution, whereby the caller can find out the new balance from MachineState. Corrected some code in FunctionCode to get current balance from MachineState instead in light of above. (Ditto previousBalance). Added MAX_STEPS to MachineState to ATs can be made to sleep if they execute too many steps in one execution round. Added some pre-execution checks to MachineState.execute() to prevent execution in some cases, like already finished, or not enough balance to un-freeze, or not reached required block while sleeping, etc. Unit tests pass, but there are no test for new steps/fee code yet!
This commit is contained in:
parent
454d4bed35
commit
297ccbdaf6
@ -12,6 +12,12 @@ package org.ciyam.at;
|
||||
*/
|
||||
public abstract class API {
|
||||
|
||||
/** Returns fee for executing opcode in terms of execution "steps" */
|
||||
public abstract int getOpCodeSteps(OpCode opcode);
|
||||
|
||||
/** Returns fee per execution "step" */
|
||||
public abstract long getFeePerStep();
|
||||
|
||||
/** Returns current blockchain's height */
|
||||
public abstract int getCurrentBlockHeight();
|
||||
|
||||
@ -62,17 +68,8 @@ public abstract class API {
|
||||
/** Return AT's current balance */
|
||||
public abstract long getCurrentBalance(MachineState state);
|
||||
|
||||
/** Return AT's previous balance at end of last execution round. Does not include any amounts sent to AT since */
|
||||
public abstract long getPreviousBalance(MachineState state);
|
||||
|
||||
/** Pay passed amount, or current balance if necessary, (fee inclusive) to address in B */
|
||||
public abstract void payAmountToB(long value1, MachineState state);
|
||||
|
||||
/** Pay AT's current balance to address in B */
|
||||
public abstract void payCurrentBalanceToB(MachineState state);
|
||||
|
||||
/** Pay AT's previous balance to address in B */
|
||||
public abstract void payPreviousBalanceToB(MachineState state);
|
||||
public abstract void payAmountToB(long amount, MachineState state);
|
||||
|
||||
/** Send 'message' in A to address in B */
|
||||
public abstract void messageAToB(MachineState state);
|
||||
@ -84,7 +81,10 @@ public abstract class API {
|
||||
*/
|
||||
public abstract long addMinutesToTimestamp(Timestamp timestamp, long minutes, MachineState state);
|
||||
|
||||
/** AT has encountered fatal error. Return remaining funds to creator */
|
||||
/** AT has finished. Return remaining funds to creator */
|
||||
public abstract void onFinished(long amount, MachineState state);
|
||||
|
||||
/** AT has encountered fatal error */
|
||||
public abstract void onFatalError(MachineState state, ExecutionException e);
|
||||
|
||||
/** Pre-execute checking of param requirements for platform-specific functions */
|
||||
@ -92,7 +92,7 @@ public abstract class API {
|
||||
throws IllegalFunctionCodeException;
|
||||
|
||||
/**
|
||||
* Platform-specific function execution
|
||||
* Platform-specific function execution after checking correct calling OpCode
|
||||
*
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
@ -103,6 +103,11 @@ public abstract class API {
|
||||
state.setIsSleeping(isSleeping);
|
||||
}
|
||||
|
||||
/** Convenience method to allow subclasses to test package-scoped MachineState.isFirstOpCodeAfterSleeping */
|
||||
protected boolean isFirstOpCodeAfterSleeping(MachineState state) {
|
||||
return state.isFirstOpCodeAfterSleeping();
|
||||
}
|
||||
|
||||
/** Convenience methods to allow subclasses to access package-scoped a1-a4, b1-b4 variables */
|
||||
protected void setA1(MachineState state, long value) {
|
||||
state.a1 = value;
|
||||
|
@ -810,7 +810,7 @@ public enum FunctionCode {
|
||||
GET_CURRENT_BALANCE(0x0400, 0, true) {
|
||||
@Override
|
||||
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
|
||||
functionData.returnValue = state.getAPI().getCurrentBalance(state);
|
||||
functionData.returnValue = state.getCurrentBalance();
|
||||
}
|
||||
},
|
||||
/**
|
||||
@ -821,7 +821,7 @@ public enum FunctionCode {
|
||||
GET_PREVIOUS_BALANCE(0x0401, 0, true) {
|
||||
@Override
|
||||
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
|
||||
functionData.returnValue = state.getAPI().getPreviousBalance(state);
|
||||
functionData.returnValue = state.getPreviousBalance();
|
||||
}
|
||||
},
|
||||
/**
|
||||
@ -832,7 +832,18 @@ public enum FunctionCode {
|
||||
PAY_TO_ADDRESS_IN_B(0x0402, 1, false) {
|
||||
@Override
|
||||
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
|
||||
state.getAPI().payAmountToB(functionData.value1, state);
|
||||
// Reduce amount to current balance if insufficient funds to pay full amount in value1
|
||||
long amount = Math.max(state.getCurrentBalance(), functionData.value1);
|
||||
|
||||
// Actually pay
|
||||
state.getAPI().payAmountToB(amount, state);
|
||||
|
||||
// Update current balance to reflect payment
|
||||
state.setCurrentBalance(state.getCurrentBalance() - amount);
|
||||
|
||||
// With no balance left, this AT is effectively finished?
|
||||
if (state.getCurrentBalance() == 0)
|
||||
state.setIsFinished(true);
|
||||
}
|
||||
},
|
||||
/**
|
||||
@ -842,7 +853,11 @@ public enum FunctionCode {
|
||||
PAY_ALL_TO_ADDRESS_IN_B(0x0403, 0, false) {
|
||||
@Override
|
||||
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
|
||||
state.getAPI().payCurrentBalanceToB(state);
|
||||
state.getAPI().payAmountToB(state.getCurrentBalance(), state);
|
||||
|
||||
// With no balance left, this AT is effectively finished?
|
||||
state.setCurrentBalance(0);
|
||||
state.setIsFinished(true);
|
||||
}
|
||||
},
|
||||
/**
|
||||
@ -853,7 +868,18 @@ public enum FunctionCode {
|
||||
PAY_PREVIOUS_TO_ADDRESS_IN_B(0x0404, 0, false) {
|
||||
@Override
|
||||
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
|
||||
state.getAPI().payPreviousBalanceToB(state);
|
||||
// Reduce amount to previous balance if insufficient funds to pay previous balance amount
|
||||
long amount = Math.max(state.getCurrentBalance(), state.getPreviousBalance());
|
||||
|
||||
// Actually pay
|
||||
state.getAPI().payAmountToB(amount, state);
|
||||
|
||||
// Update current balance to reflect payment
|
||||
state.setCurrentBalance(state.getCurrentBalance() - amount);
|
||||
|
||||
// With no balance left, this AT is effectively finished?
|
||||
if (state.getCurrentBalance() == 0)
|
||||
state.setIsFinished(true);
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
@ -26,7 +26,10 @@ public class MachineState {
|
||||
public static final int ADDRESS_SIZE = 4;
|
||||
|
||||
/** Maximum value for an address in the code segment */
|
||||
public static final int MAX_CODE_ADDRESS = 0x1fffffff;
|
||||
public static final int MAX_CODE_ADDRESS = 0x0000ffff;
|
||||
|
||||
/** Maximum number of steps per execution round */
|
||||
public static final int MAX_STEPS = 500;
|
||||
|
||||
private static class VersionedConstants {
|
||||
/** Bytes per code page */
|
||||
@ -109,11 +112,18 @@ public class MachineState {
|
||||
/* package */ long b3;
|
||||
/* package */ long b4;
|
||||
|
||||
// Internal use
|
||||
private int currentBlockHeight;
|
||||
private long currentBalance;
|
||||
|
||||
/** Number of opcodes processed this execution */
|
||||
/** Previous balance after end of last round of execution */
|
||||
private long previousBalance;
|
||||
|
||||
/** Number of opcodes processed this execution round */
|
||||
private int steps;
|
||||
|
||||
private boolean isFirstOpCodeAfterSleeping;
|
||||
|
||||
private API api;
|
||||
private LoggerInterface logger;
|
||||
|
||||
@ -175,6 +185,8 @@ public class MachineState {
|
||||
|
||||
this.api = api;
|
||||
this.currentBlockHeight = 0;
|
||||
this.currentBalance = 0;
|
||||
this.previousBalance = 0;
|
||||
this.steps = 0;
|
||||
this.logger = logger;
|
||||
}
|
||||
@ -223,6 +235,7 @@ public class MachineState {
|
||||
this.frozenBalance = null;
|
||||
this.isFinished = false;
|
||||
this.hadFatalError = false;
|
||||
this.previousBalance = 0;
|
||||
}
|
||||
|
||||
// Getters / setters
|
||||
@ -344,6 +357,7 @@ public class MachineState {
|
||||
return this.currentBlockHeight;
|
||||
}
|
||||
|
||||
/** So API can determine final execution fee */
|
||||
public int getSteps() {
|
||||
return this.steps;
|
||||
}
|
||||
@ -356,6 +370,25 @@ public class MachineState {
|
||||
return this.logger;
|
||||
}
|
||||
|
||||
public long getCurrentBalance() {
|
||||
return this.currentBalance;
|
||||
}
|
||||
|
||||
// For FunctionCode use
|
||||
/* package */ void setCurrentBalance(long currentBalance) {
|
||||
this.currentBalance = currentBalance;
|
||||
}
|
||||
|
||||
// For FunctionCode use
|
||||
/* package */ long getPreviousBalance() {
|
||||
return this.previousBalance;
|
||||
}
|
||||
|
||||
// For FunctionCode/API use
|
||||
/* package */ boolean isFirstOpCodeAfterSleeping() {
|
||||
return this.isFirstOpCodeAfterSleeping;
|
||||
}
|
||||
|
||||
// Serialization
|
||||
|
||||
/** For serializing a machine state */
|
||||
@ -387,6 +420,7 @@ public class MachineState {
|
||||
// Actual state
|
||||
bytes.write(toByteArray(this.programCounter));
|
||||
bytes.write(toByteArray(this.onStopAddress));
|
||||
bytes.write(toByteArray(this.previousBalance));
|
||||
|
||||
// Various flags
|
||||
Flags flags = new Flags();
|
||||
@ -474,6 +508,7 @@ public class MachineState {
|
||||
// Actual state
|
||||
state.programCounter = byteBuffer.getInt();
|
||||
state.onStopAddress = byteBuffer.getInt();
|
||||
state.previousBalance = byteBuffer.getLong();
|
||||
|
||||
// Various flags (reverse order to toBytes)
|
||||
Flags flags = state.new Flags(byteBuffer.getInt());
|
||||
@ -555,11 +590,39 @@ public class MachineState {
|
||||
(byte) (value >> 48), (byte) (value >> 56) };
|
||||
}
|
||||
|
||||
// Actual execution
|
||||
|
||||
/**
|
||||
* Actually perform a round of execution
|
||||
* <p>
|
||||
* On return, caller is expected to call getCurrentBalance() to update their account records, and also to call getSteps() to calculate final execution fee
|
||||
* for block records.
|
||||
*/
|
||||
public void execute() {
|
||||
// Set byte buffer position using program counter
|
||||
codeByteBuffer.position(this.programCounter);
|
||||
// Initialization
|
||||
this.steps = 0;
|
||||
this.currentBlockHeight = api.getCurrentBlockHeight();
|
||||
this.currentBalance = api.getCurrentBalance(this);
|
||||
this.isFirstOpCodeAfterSleeping = false;
|
||||
|
||||
// Pre-execution checks
|
||||
if (this.isFinished) {
|
||||
logger.debug("Not executing as already finished!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isFrozen && this.currentBalance <= this.frozenBalance) {
|
||||
logger.debug("Not executing as current balance [" + this.currentBalance + "] hasn't increased since being frozen at [" + this.frozenBalance + "]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isSleeping && this.sleepUntilHeight != null && this.currentBlockHeight < this.sleepUntilHeight) {
|
||||
logger.debug("Not executing as current block height [" + this.currentBlockHeight + "] hasn't reached sleep-until block height ["
|
||||
+ this.sleepUntilHeight + "]");
|
||||
return;
|
||||
}
|
||||
|
||||
// If we were previously sleeping then set first-opcode-after-sleeping to help FunctionCodes that need to detect this
|
||||
if (this.isSleeping)
|
||||
this.isFirstOpCodeAfterSleeping = true;
|
||||
|
||||
// Reset for this round of execution
|
||||
this.isSleeping = false;
|
||||
@ -567,8 +630,11 @@ public class MachineState {
|
||||
this.isStopped = false;
|
||||
this.isFrozen = false;
|
||||
this.frozenBalance = null;
|
||||
this.steps = 0;
|
||||
this.currentBlockHeight = api.getCurrentBlockHeight();
|
||||
|
||||
long feePerStep = this.api.getFeePerStep();
|
||||
|
||||
// Set byte buffer position using program counter
|
||||
codeByteBuffer.position(this.programCounter);
|
||||
|
||||
while (!this.isSleeping && !this.isStopped && !this.isFinished && !this.isFrozen) {
|
||||
byte rawOpCode = codeByteBuffer.get();
|
||||
@ -580,7 +646,27 @@ public class MachineState {
|
||||
|
||||
this.logger.debug("[PC: " + String.format("%04x", this.programCounter) + "] " + nextOpCode.name());
|
||||
|
||||
// TODO: Request cost from API, apply cost to balance, etc.
|
||||
// Request opcode step-fee from API, apply fee to balance, etc.
|
||||
int opcodeSteps = this.api.getOpCodeSteps(nextOpCode);
|
||||
long opcodeFee = opcodeSteps * feePerStep;
|
||||
|
||||
if (this.steps + opcodeSteps > MAX_STEPS) {
|
||||
logger.debug("Enforced sleep due to exceeding maximum number of steps (" + MAX_STEPS + ") per execution round");
|
||||
this.isSleeping = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.currentBalance < opcodeFee) {
|
||||
// Not enough balance left to continue execution - freeze AT
|
||||
logger.debug("Frozen due to lack of balance");
|
||||
this.isFrozen = true;
|
||||
this.frozenBalance = this.currentBalance;
|
||||
break;
|
||||
}
|
||||
|
||||
// Apply opcode step-fee
|
||||
this.currentBalance -= opcodeFee;
|
||||
this.steps += opcodeSteps;
|
||||
|
||||
// At this point, programCounter is BEFORE opcode (and args).
|
||||
nextOpCode.execute(this);
|
||||
@ -594,7 +680,7 @@ public class MachineState {
|
||||
this.isFinished = true;
|
||||
this.hadFatalError = true;
|
||||
|
||||
// Ask API to refund remaining funds back to AT's creator
|
||||
// Notify API that there was an error
|
||||
this.api.onFatalError(this, e);
|
||||
break;
|
||||
}
|
||||
@ -603,13 +689,30 @@ public class MachineState {
|
||||
codeByteBuffer.position(this.programCounter);
|
||||
}
|
||||
|
||||
++this.steps;
|
||||
// No longer true
|
||||
this.isFirstOpCodeAfterSleeping = false;
|
||||
}
|
||||
|
||||
if (this.isSleeping) {
|
||||
if (this.sleepUntilHeight != null)
|
||||
this.logger.debug("Sleeping until block " + this.sleepUntilHeight);
|
||||
else
|
||||
this.logger.debug("Sleeping until next block");
|
||||
}
|
||||
|
||||
if (this.isStopped) {
|
||||
this.logger.debug("Setting program counter to stop address: " + String.format("%04x", this.onStopAddress));
|
||||
this.programCounter = this.onStopAddress;
|
||||
}
|
||||
|
||||
if (this.isFinished) {
|
||||
this.logger.debug("Finished - refunding remaining funds back to creator");
|
||||
this.api.onFinished(this.currentBalance, this);
|
||||
this.currentBalance = 0;
|
||||
}
|
||||
|
||||
// Set new value for previousBalance prior to serialization, ready for next round
|
||||
this.previousBalance = this.currentBalance;
|
||||
}
|
||||
|
||||
/** Return disassembly of code bytes */
|
||||
|
@ -71,6 +71,8 @@ public class TestACCT {
|
||||
private byte[] executeAndCheck(MachineState state) {
|
||||
state.execute();
|
||||
|
||||
api.setCurrentBalance(state.getCurrentBalance());
|
||||
|
||||
byte[] stateBytes = state.toBytes();
|
||||
MachineState restoredState = MachineState.fromBytes(api, logger, stateBytes);
|
||||
byte[] restoredStateBytes = restoredState.toBytes();
|
||||
|
@ -12,6 +12,7 @@ import org.ciyam.at.ExecutionException;
|
||||
import org.ciyam.at.FunctionData;
|
||||
import org.ciyam.at.IllegalFunctionCodeException;
|
||||
import org.ciyam.at.MachineState;
|
||||
import org.ciyam.at.OpCode;
|
||||
import org.ciyam.at.Timestamp;
|
||||
|
||||
public class ACCTAPI extends API {
|
||||
@ -46,7 +47,6 @@ public class ACCTAPI extends API {
|
||||
private List<Block> blockchain;
|
||||
private Map<String, Account> accounts;
|
||||
private long balanceAT;
|
||||
private long previousBalanceAT;
|
||||
|
||||
//
|
||||
public ACCTAPI() {
|
||||
@ -68,8 +68,10 @@ public class ACCTAPI extends API {
|
||||
Account bystander = new Account("Bystander", 999);
|
||||
this.accounts.put(bystander.address, bystander);
|
||||
|
||||
Account creator = new Account("Creator", 0);
|
||||
this.accounts.put(creator.address, creator);
|
||||
|
||||
this.balanceAT = 50000;
|
||||
this.previousBalanceAT = this.balanceAT;
|
||||
}
|
||||
|
||||
public void generateNextBlock(byte[] secret) {
|
||||
@ -125,8 +127,6 @@ public class ACCTAPI extends API {
|
||||
}
|
||||
|
||||
this.blockchain.add(block);
|
||||
|
||||
this.previousBalanceAT = this.balanceAT;
|
||||
}
|
||||
|
||||
/** Convert long to little-endian byte array */
|
||||
@ -150,6 +150,16 @@ public class ACCTAPI extends API {
|
||||
return accounts.get(accountIndex).address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpCodeSteps(OpCode opcode) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFeePerStep() {
|
||||
return 1L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentBlockHeight() {
|
||||
return this.blockchain.size();
|
||||
@ -274,29 +284,24 @@ public class ACCTAPI extends API {
|
||||
return this.balanceAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPreviousBalance(MachineState state) {
|
||||
return this.previousBalanceAT;
|
||||
public void setCurrentBalance(long balance) {
|
||||
this.balanceAT = balance;
|
||||
System.out.println("New AT balance: " + balance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payAmountToB(long value1, MachineState state) {
|
||||
char firstChar = String.format("%c", state.getB1()).charAt(0);
|
||||
public void payAmountToB(long amount, MachineState state) {
|
||||
// Determine recipient using first char in B1
|
||||
char firstChar = String.format("%c", (byte) state.getB1()).charAt(0);
|
||||
Account recipient = this.accounts.values().stream().filter((account) -> account.address.charAt(0) == firstChar).findFirst().get();
|
||||
recipient.balance += value1;
|
||||
System.out.println("Paid " + value1 + " to " + recipient.address + ", their balance now: " + recipient.balance);
|
||||
this.balanceAT -= value1;
|
||||
System.out.println("Our balance now: " + this.balanceAT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payCurrentBalanceToB(MachineState state) {
|
||||
// NOT USED
|
||||
}
|
||||
// Simulate payment
|
||||
recipient.balance += amount;
|
||||
System.out.println("Paid " + amount + " to " + recipient.address + ", their balance now: " + recipient.balance);
|
||||
|
||||
@Override
|
||||
public void payPreviousBalanceToB(MachineState state) {
|
||||
// NOT USED
|
||||
// For debugging, output our new balance
|
||||
long balance = state.getCurrentBalance() - amount;
|
||||
System.out.println("Our balance now: " + balance);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -310,10 +315,19 @@ public class ACCTAPI extends API {
|
||||
return timestamp.longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(long amount, MachineState state) {
|
||||
System.out.println("Finished - refunding remaining to creator");
|
||||
|
||||
Account creator = this.accounts.get("Creator");
|
||||
creator.balance += amount;
|
||||
System.out.println("Paid " + amount + " to " + creator.address + ", their balance now: " + creator.balance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFatalError(MachineState state, ExecutionException e) {
|
||||
System.out.println("Fatal error: " + e.getMessage());
|
||||
System.out.println("No error address set - refunding to creator and finishing");
|
||||
System.out.println("No error address set - will refund to creator and finish");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,6 +5,7 @@ import org.ciyam.at.ExecutionException;
|
||||
import org.ciyam.at.FunctionData;
|
||||
import org.ciyam.at.IllegalFunctionCodeException;
|
||||
import org.ciyam.at.MachineState;
|
||||
import org.ciyam.at.OpCode;
|
||||
import org.ciyam.at.Timestamp;
|
||||
|
||||
public class TestAPI extends API {
|
||||
@ -21,6 +22,19 @@ public class TestAPI extends API {
|
||||
++this.currentBlockHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpCodeSteps(OpCode opcode) {
|
||||
if (opcode.value >= OpCode.EXT_FUN.value && opcode.value <= OpCode.EXT_FUN_RET_DAT_2.value)
|
||||
return 10;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFeePerStep() {
|
||||
return 1L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentBlockHeight() {
|
||||
return this.currentBlockHeight;
|
||||
@ -65,7 +79,7 @@ public class TestAPI extends API {
|
||||
|
||||
@Override
|
||||
public long generateRandomUsingTransactionInA(MachineState state) {
|
||||
if (state.getSteps() != 0) {
|
||||
if (isFirstOpCodeAfterSleeping(state)) {
|
||||
// First call
|
||||
System.out.println("generateRandomUsingTransactionInA: first call - sleeping");
|
||||
|
||||
@ -115,20 +129,7 @@ public class TestAPI extends API {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPreviousBalance(MachineState state) {
|
||||
return 10000L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payAmountToB(long value1, MachineState state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payCurrentBalanceToB(MachineState state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payPreviousBalanceToB(MachineState state) {
|
||||
public void payAmountToB(long amount, MachineState state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -141,10 +142,15 @@ public class TestAPI extends API {
|
||||
return timestamp.longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(long amount, MachineState state) {
|
||||
System.out.println("Finished - refunding remaining to creator");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFatalError(MachineState state, ExecutionException e) {
|
||||
System.out.println("Fatal error: " + e.getMessage());
|
||||
System.out.println("No error address set - refunding to creator and finishing");
|
||||
System.out.println("No error address set - will refund to creator and finish");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user