Skip to content
This repository was archived by the owner on Aug 30, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion eosiojava/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies {
api 'com.google.code.gson:gson:2.8.5'
api 'org.bouncycastle:bcprov-jdk15on:1.61'
api 'org.bouncycastle:bcpkix-jdk15on:1.61'
api 'com.vdurmont:semver4j:3.1.0'
// This works on android and non-android, but is necessary to keep us to 1.7 targets.
api 'com.google.guava:guava:27.1-android'
testCompile 'junit:junit:4.12'
Expand All @@ -47,7 +48,7 @@ test {

def libraryGroupId = 'one.block'
def libraryArtifactId = 'eosiojava'
def libraryVersion = '1.0.0'
def libraryVersion = '1.0.1'

task sourcesJar(type: Jar, dependsOn: classes){
classifier = 'sources'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ private ErrorConstants(){
*/
public static final String TRANSACTION_PROCESSOR_PREPARE_RPC_GET_BLOCK_INFO = "Error happened on calling GetBlockInfo RPC.";

/**
* Error message get thrown if {@link IRPCProvider#getBlock(GetBlockRequest)} thrown exception during process of {@link TransactionProcessor#prepare(List)}
*/
public static final String TRANSACTION_PROCESSOR_PREPARE_RPC_GET_BLOCK = "Error happened on calling GetBlock RPC.";

/**
* Error message get thrown if chain id from {@link GetInfoResponse#getChainId()} does not match with the input chain id
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package one.block.eosiojava.interfaces;

import one.block.eosiojava.error.rpcProvider.GetBlockInfoRpcError;
import one.block.eosiojava.error.rpcProvider.GetBlockRpcError;
import one.block.eosiojava.error.rpcProvider.GetInfoRpcError;
import one.block.eosiojava.error.rpcProvider.GetRawAbiRpcError;
import one.block.eosiojava.error.rpcProvider.GetRequiredKeysRpcError;
import one.block.eosiojava.error.rpcProvider.SendTransactionRpcError;
import one.block.eosiojava.models.rpcProvider.request.GetBlockInfoRequest;
import one.block.eosiojava.models.rpcProvider.request.GetBlockRequest;
import one.block.eosiojava.models.rpcProvider.request.GetRawAbiRequest;
import one.block.eosiojava.models.rpcProvider.request.GetRequiredKeysRequest;
import one.block.eosiojava.models.rpcProvider.request.SendTransactionRequest;

import one.block.eosiojava.models.rpcProvider.response.GetBlockInfoResponse;
import one.block.eosiojava.models.rpcProvider.response.GetBlockResponse;
import one.block.eosiojava.models.rpcProvider.response.GetInfoResponse;
import one.block.eosiojava.models.rpcProvider.response.GetRawAbiResponse;
import one.block.eosiojava.models.rpcProvider.response.GetRequiredKeysResponse;
Expand Down Expand Up @@ -43,6 +46,17 @@ public interface IRPCProvider {
@NotNull
GetBlockInfoResponse getBlockInfo(GetBlockInfoRequest getBlockInfoRequest) throws GetBlockInfoRpcError;

/**
* Returns an object containing various details about a specific block on the blockchain.
*
* @param getBlockRequest Info of a specific block.
* @return the info/status of a specific block in the request
* @throws GetBlockRpcError thrown if there are any exceptions/backend error during the
* getBlockInfo() process.
*/
@NotNull
GetBlockResponse getBlock(GetBlockRequest getBlockRequest) throws GetBlockRpcError;

/**
* Gets raw abi for a given contract.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ public class TransactionConfig {
*/
private static final boolean DEFAULT_USE_LAST_IRREVERSIBLE = true;

/**
* Default chain version string to use if none is specified and we cannot get the server version from
* the chain itself.
*/
private static final String DEFAULT_CHAIN_VERSION_STRING = "2.0.0";

/**
* Chain version at which {@link one.block.eosiojava.interfaces.IRPCProvider#getBlockInfo(GetBlockInfoRequest)}
* became available.
*/
private static final String GET_BLOCK_INFO_AVAILABLE_STRING = "2.1.0";

/**
* The Expires seconds.
* <br>
Expand All @@ -55,6 +67,15 @@ public class TransactionConfig {
*/
private boolean useLastIrreversible = DEFAULT_USE_LAST_IRREVERSIBLE;

/**
* Version of nodeos that the transaction is targeting. This will allow the library to work with 2.1+ version
* chains using {@link one.block.eosiojava.interfaces.IRPCProvider#getBlockInfo(GetBlockInfoRequest)} for
* calculating TAPOS rather than {@link one.block.eosiojava.interfaces.IRPCProvider#getBlock(GetBlockInfoRequest)}.
* If the value is left unset, the transaction will determine the chain version from the {@link IRPCProvider#getInfo()} call
* and use that as the chain version string.
*/
private String chainVersionString = null;

/**
* Gets the expiration time for the transaction.
* <br>
Expand Down Expand Up @@ -117,4 +138,41 @@ public void setBlocksBehind(int blocksBehind) {
public void setUseLastIrreversible(boolean useLastIrreversible) {
this.useLastIrreversible = useLastIrreversible;
}

/**
* Gets the current chain version that the transaction is targeting.
* <br>
* 2.1+ version chains will use {@link one.block.eosiojava.interfaces.IRPCProvider#getBlockInfo(GetBlockInfoRequest)} for
* calculating TAPOS rather than {@link one.block.eosiojava.interfaces.IRPCProvider#getBlock(GetBlockRequest)}. If
* the value is left unset, the transaction will determine the chain version from the {@link IRPCProvider#getInfo()} call
* and use that as the chain version string.
* @return chainVersionString current nodeos version that we are targeting for this transaction
*/
public String getChainVersionString() { return chainVersionString; }

/**
* Sets the current chain version that the transaction is targeting.
* <br>
* 2.1+ version chains will use {@link one.block.eosiojava.interfaces.IRPCProvider#getBlockInfo(GetBlockInfoRequest)} for
* calculating TAPOS rather than {@link one.block.eosiojava.interfaces.IRPCProvider#getBlock(GetBlockRequest)}. If
* the value is left unset, the transaction will determine the chain version from the {@link IRPCProvider#getInfo()} call
* and use that as the chain version string.
* @param chainVersionString set the target nodeos version that this transaction is for
*/
public void setChainVersionString(String chainVersionString) { this.chainVersionString = chainVersionString; }

/**
* Get the default chain version string to use for transactions if one is not specified and the version cannot
* be read from the chain itself.
* @return defaultChainVersionString the version of nodeos if one is not set and the version cannot be read from the chain itself.
*/
public String getDefaultChainVersionString() { return DEFAULT_CHAIN_VERSION_STRING; }

/**
* Chain version at which {@link one.block.eosiojava.interfaces.IRPCProvider#getBlockInfo(GetBlockInfoRequest)}
* became available.
* @return getBlockInfoAvailableString the version of nodeos where {@link one.block.eosiojava.interfaces.IRPCProvider#getBlockInfo(GetBlockInfoRequest)}
* became available.
*/
public String getGetBlockInfoAvailableString() { return GET_BLOCK_INFO_AVAILABLE_STRING; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.jetbrains.annotations.NotNull;

/**
* The request class for getBlock() RPC call {@link one.block.eosiojava.interfaces.IRPCProvider#getBlockInfo(GetBlockInfoRequest)}
* The request class for getBlock() RPC call {@link one.block.eosiojava.interfaces.IRPCProvider#getBlock(GetBlockRequest)}
*/
public class GetBlockRequest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import com.vdurmont.semver4j.Semver;
import com.vdurmont.semver4j.SemverException;
import one.block.eosiojava.error.ErrorConstants;
import one.block.eosiojava.error.abiProvider.GetAbiError;
import one.block.eosiojava.error.rpcProvider.GetBlockInfoRpcError;
import one.block.eosiojava.error.rpcProvider.GetBlockRpcError;
import one.block.eosiojava.error.rpcProvider.GetInfoRpcError;
import one.block.eosiojava.error.rpcProvider.GetRequiredKeysRpcError;
import one.block.eosiojava.error.rpcProvider.SendTransactionRpcError;
Expand Down Expand Up @@ -51,9 +55,15 @@
import one.block.eosiojava.models.rpcProvider.ContextFreeData;
import one.block.eosiojava.models.rpcProvider.TransactionConfig;
import one.block.eosiojava.models.rpcProvider.request.GetBlockInfoRequest;
import one.block.eosiojava.models.rpcProvider.request.GetBlockRequest;
import one.block.eosiojava.models.rpcProvider.request.GetRequiredKeysRequest;
import one.block.eosiojava.models.rpcProvider.request.SendTransactionRequest;
import one.block.eosiojava.models.rpcProvider.response.*;

import one.block.eosiojava.models.rpcProvider.response.GetBlockInfoResponse;
import one.block.eosiojava.models.rpcProvider.response.GetBlockResponse;
import one.block.eosiojava.models.rpcProvider.response.GetInfoResponse;
import one.block.eosiojava.models.rpcProvider.response.GetRequiredKeysResponse;
import one.block.eosiojava.models.rpcProvider.response.SendTransactionResponse;
import one.block.eosiojava.models.signatureProvider.EosioTransactionSignatureRequest;
import one.block.eosiojava.models.signatureProvider.EosioTransactionSignatureResponse;
import one.block.eosiojava.utilities.DateFormatter;
Expand Down Expand Up @@ -203,6 +213,13 @@ public class TransactionProcessor {
*/
private static final String PACKED_TRANSACTION_V0_PREFIX = "00";

/**
* Index for the first character of a string, which in a version returned from
* the blockchain may contain a 'v'. If it does we will remove it before comparing
* versions against the transaction targeted version.
*/
private static final int CHAR_INDEX_V_PREFIX = 0;

/**
* Constructor with all provider references from {@link TransactionSession}
* @param serializationProvider the serialization provider.
Expand Down Expand Up @@ -374,6 +391,15 @@ public void prepare(@NotNull List<Action> actions, @NotNull List<Action> context
getInfoResponse.getChainId()));
}

String chainVersionString = this.transactionConfig.getChainVersionString();
if (Strings.isNullOrEmpty(chainVersionString)) {
if (Strings.isNullOrEmpty(getInfoResponse.getServerVersion())) {
chainVersionString = this.transactionConfig.getDefaultChainVersionString();
} else {
chainVersionString = getInfoResponse.getServerVersionString();
}
}

// Assigning value to refBlockNum and refBlockPrefix

BigInteger taposBlockNum;
Expand All @@ -393,20 +419,55 @@ public void prepare(@NotNull List<Action> actions, @NotNull List<Action> context
}
}

GetBlockInfoResponse getBlockInfoResponse;

boolean useGetBlockInfo = false;
// Remove any leading non-digit character.
if (!Character.isDigit(chainVersionString.charAt(CHAR_INDEX_V_PREFIX))) {
chainVersionString = chainVersionString.substring(1);
}
try {
getBlockInfoResponse = this.rpcProvider
.getBlockInfo(new GetBlockInfoRequest(taposBlockNum));
} catch (GetBlockInfoRpcError getBlockInfoRpcError) {
throw new TransactionPrepareRpcError(
ErrorConstants.TRANSACTION_PROCESSOR_PREPARE_RPC_GET_BLOCK_INFO, getBlockInfoRpcError);
// Strip any kind of beta or rc suffix.
Semver chainVersion = new Semver(chainVersionString).withClearedSuffix();
Semver getBlockInfoAvailableVersion = new Semver(this.transactionConfig.getGetBlockInfoAvailableString());
useGetBlockInfo = chainVersion.isGreaterThanOrEqualTo(getBlockInfoAvailableVersion);
} catch (SemverException semverException) {
// Default back to getBlock as the safer alternative for now.
useGetBlockInfo = false;
}

String strHeadBlockTime;
BigInteger blockNum;
BigInteger refBlockPrefix;

if (useGetBlockInfo) {
GetBlockInfoResponse getBlockInfoResponse;
try {
getBlockInfoResponse = this.rpcProvider
.getBlockInfo(new GetBlockInfoRequest(taposBlockNum));
strHeadBlockTime = getBlockInfoResponse.getTimestamp();
blockNum = getBlockInfoResponse.getBlockNum();
refBlockPrefix = getBlockInfoResponse.getRefBlockPrefix();
} catch (GetBlockInfoRpcError getBlockInfoRpcError) {
throw new TransactionPrepareRpcError(
ErrorConstants.TRANSACTION_PROCESSOR_PREPARE_RPC_GET_BLOCK_INFO, getBlockInfoRpcError);
}
} else {
GetBlockResponse getBlockResponse;
try {
getBlockResponse = this.rpcProvider
.getBlock(new GetBlockRequest(taposBlockNum.toString()));
strHeadBlockTime = getBlockResponse.getTimestamp();
blockNum = getBlockResponse.getBlockNum();
refBlockPrefix = getBlockResponse.getRefBlockPrefix();
} catch (GetBlockRpcError getBlockRpcError) {
throw new TransactionPrepareRpcError(
ErrorConstants.TRANSACTION_PROCESSOR_PREPARE_RPC_GET_BLOCK, getBlockRpcError);
}
}

// Calculate the expiration based on the taposBlockNum expiration
if (preparingTransaction.getExpiration().isEmpty()) {

String strHeadBlockTime = getBlockInfoResponse.getTimestamp();

long taposBlockTime;

try {
Expand All @@ -424,8 +485,7 @@ public void prepare(@NotNull List<Action> actions, @NotNull List<Action> context
}

// Restrict the refBlockNum to 32 bit unsigned value
BigInteger refBlockNum = getBlockInfoResponse.getBlockNum().and(BigInteger.valueOf(0xffff));
BigInteger refBlockPrefix = getBlockInfoResponse.getRefBlockPrefix();
BigInteger refBlockNum = blockNum.and(BigInteger.valueOf(0xffff));

preparingTransaction.setRefBlockNum(refBlockNum);
preparingTransaction.setRefBlockPrefix(refBlockPrefix);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public void prepare_thenFailWithWrongDateFormat() throws TransactionPrepareError

String weirdHeadBlockTime = "2019-04-01TGM22:08:40.000";
String mockedGetInfoResponseWithWeirdDateFormat = "{\n"
+ " \"server_version\": \"1\",\n"
+ " \"server_version\": \"2\",\n"
+ " \"chain_id\": \"sample chain id\",\n"
+ " \"head_block_num\": " + headBlockNum + ",\n"
+ " \"last_irreversible_block_num\": 1,\n"
Expand All @@ -149,7 +149,7 @@ public void prepare_thenFailWithWrongDateFormat() throws TransactionPrepareError
+ " \"virtual_block_net_limit\": 1,\n"
+ " \"block_cpu_limit\": 1,\n"
+ " \"block_net_limit\": 1,\n"
+ " \"server_version_string\": \"v1.3.0\"\n"
+ " \"server_version_string\": \"v2.1.0\"\n"
+ "}";

String mockedGetBlockInfoResponseWithWeirdDateFormat = "{\n"
Expand Down Expand Up @@ -595,7 +595,7 @@ private List<Action> defaultActions() {
.and(BigInteger.valueOf(0xffff));

private static final String mockedGetInfoResponse = "{\n"
+ " \"server_version\": \"1\",\n"
+ " \"server_version\": \"2\",\n"
+ " \"chain_id\": \"sample chain id\",\n"
+ " \"head_block_num\": " + headBlockNum + ",\n"
+ " \"last_irreversible_block_num\": 1,\n"
Expand All @@ -607,7 +607,7 @@ private List<Action> defaultActions() {
+ " \"virtual_block_net_limit\": 1,\n"
+ " \"block_cpu_limit\": 1,\n"
+ " \"block_net_limit\": 1,\n"
+ " \"server_version_string\": \"v1.3.0\"\n"
+ " \"server_version_string\": \"v2.1.0\"\n"
+ "}";

private static final String mockedGetBlockInfoResponse = "{\n"
Expand Down
Loading