Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -537,4 +537,22 @@ public static String generateFilterId() {
random.nextBytes(uid);
return ByteArray.toHexString(uid);
}

/**
* Check if transaction data parameter is null or empty
* Supports both 'data' and 'input' parameters
*/
public static boolean paramTransactionDataIsNull(String data, String input) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These helpers(paramTransactionDataIsNull and getTransactionData) look like the intended canonical implementation, but they are not actually used by CallArguments / BuildArguments.

Right now the PR adds a shared utility and still keeps separate local implementations, and those implementations already differ on "0x" semantics. Please either:

  • make this utility the single source of truth, or
  • remove it

but avoid leaving the refactor half-done.

return paramStringIsNull(data) && paramStringIsNull(input);
}

/**
* Get transaction data with priority: input > data
*/
public static String getTransactionData(String data, String input) {
if (!paramStringIsNull(input)) {
return input;
}
return data;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -604,15 +604,15 @@ public String estimateGas(CallArguments args) throws JsonRpcInvalidRequestExcept
estimateEnergy(ownerAddress,
contractAddress,
args.parseValue(),
ByteArray.fromHexString(args.getData()),
ByteArray.fromHexString(args.getTransactionData()),
trxExtBuilder,
retBuilder,
estimateBuilder);
} else {
callTriggerConstantContract(ownerAddress,
contractAddress,
args.parseValue(),
ByteArray.fromHexString(args.getData()),
ByteArray.fromHexString(args.getTransactionData()),
trxExtBuilder,
retBuilder);
}
Expand Down Expand Up @@ -838,7 +838,7 @@ public String getCall(CallArguments transactionCall, Object blockParamObj)
byte[] contractAddressData = addressCompatibleToByteArray(transactionCall.getTo());

return call(addressData, contractAddressData, transactionCall.parseValue(),
ByteArray.fromHexString(transactionCall.getData()));
ByteArray.fromHexString(transactionCall.getTransactionData()));
} else {
try {
ByteArray.hexToBigInteger(blockNumOrTag);
Expand Down Expand Up @@ -954,7 +954,7 @@ private TransactionJson buildCreateSmartContractTransaction(byte[] ownerAddress,
smartBuilder.setOriginAddress(ByteString.copyFrom(ownerAddress));

// bytecode + parameter
smartBuilder.setBytecode(ByteString.copyFrom(ByteArray.fromHexString(args.getData())));
smartBuilder.setBytecode(ByteString.copyFrom(ByteArray.fromHexString(args.getTransactionData())));

if (StringUtils.isNotEmpty(args.getName())) {
smartBuilder.setName(args.getName());
Expand Down Expand Up @@ -999,8 +999,8 @@ private TransactionJson buildTriggerSmartContractTransaction(byte[] ownerAddress
build.setOwnerAddress(ByteString.copyFrom(ownerAddress))
.setContractAddress(ByteString.copyFrom(contractAddress));

if (StringUtils.isNotEmpty(args.getData())) {
build.setData(ByteString.copyFrom(ByteArray.fromHexString(args.getData())));
if (StringUtils.isNotEmpty(args.getTransactionData())) {
build.setData(ByteString.copyFrom(ByteArray.fromHexString(args.getTransactionData())));
} else {
build.setData(ByteString.copyFrom(new byte[0]));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,30 @@ public class BuildArguments {
@Setter
private boolean visible = false;

@Getter
@Setter
private String input;

public BuildArguments(CallArguments args) {
from = args.getFrom();
to = args.getTo();
gas = args.getGas();
gasPrice = args.getGasPrice();
value = args.getValue();
data = args.getData();

// Use the new unified method to get transaction data for compatibility
data = args.getTransactionData();
input = args.getTransactionData();
}

/**
* Get the transaction data, supporting both 'data' and 'input' params
*/
public String getTransactionData() {
if (StringUtils.isNotEmpty(input)) {
return input;
}
return data;
}

public ContractType getContractType(Wallet wallet) throws JsonRpcInvalidRequestException,
Expand All @@ -92,7 +109,7 @@ public ContractType getContractType(Wallet wallet) throws JsonRpcInvalidRequestE
// to is null
if (paramStringIsNull(to)) {
// data is null
if (paramStringIsNull(data)) {
if (paramStringIsNull(getTransactionData())) {
throw new JsonRpcInvalidRequestException("invalid json request");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public class CallArguments {
@Getter
@Setter
private String nonce; // not used
@Getter
@Setter
private String input; //Add input parameter to align with Ethereum https://github.com/ethereum/go-ethereum/pull/28078

/**
* just support TransferContract, CreateSmartContract and TriggerSmartContract
Expand All @@ -57,8 +60,11 @@ public ContractType getContractType(Wallet wallet) throws JsonRpcInvalidRequestE
throw new JsonRpcInvalidRequestException("invalid json request");
} else if (paramStringIsNull(to)) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new input support is validated with paramStringIsNull(...), but later resolved with StringUtils.isNotEmpty(...) in getTransactionData().

Those are not equivalent in this codebase because paramStringIsNull("0x") == true, while StringUtils.isNotEmpty("0x") == true.

That creates an inconsistent flow where the request can be validated based on data, but then executed using input, silently discarding the actual calldata / bytecode.

Concrete example:

  • to == null
  • input == "0x"
  • data == "0x6080..."

Please use one canonical transaction-data resolver and one emptiness definition everywhere.

// data is null
if (paramStringIsNull(data)) {
throw new JsonRpcInvalidRequestException("invalid json request");
if (paramStringIsNull(input)) {
if(paramStringIsNull(data))
{
throw new JsonRpcInvalidRequestException("invalid json request"); //If both input and data are bnull throw an error, take input as priority
}
}

contractType = ContractType.CreateSmartContract;
Expand Down Expand Up @@ -86,4 +92,26 @@ public ContractType getContractType(Wallet wallet) throws JsonRpcInvalidRequestE
public long parseValue() throws JsonRpcInvalidParamsException {
return parseQuantityValue(value);
}

/**
* Get the transaction data, supporting both 'data' and 'input' parameters
* for Ethereum compatibility. 'input' takes precedence if both are provided.
*
* @return the transaction data/input
*/
public String getTransactionData() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The input > data priority is correct, but the conflict case is still undefined.

If both input and data are provided with different values, the current implementation silently prefers input. That makes caller mistakes hard to detect and diverges from geth, which rejects the request explicitly.

Please add a shared conflict check for:

  • both fields present
  • both non-empty under the project's own null/empty rules
  • values not equal

and return a clear params error instead of silently swallowing one side.

// Prioritize 'input' for Ethereum compatibility
if (StringUtils.isNotEmpty(input)) {
return input;
}
return data;
}

/**
* Set transaction data, updating the appropriate field based on which was used
*/
public void setTransactionData(String transactionData) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setTransactionData() is currently unused, and its name is broader than its behavior: it only writes data, not input.

That is a maintainability trap for future callers. Please either remove it, or document very explicitly why it only updates data.

// For backward compatibility, default to setting 'data'
this.data = transactionData;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void initBuildArgs() {
"0x0000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000001","0x10","0.01","0x100",
"","0",9L,10000L,"",10L,
2000L,"args",1,"",true);
2000L,"args",1,"",true,"");
}


Expand All @@ -40,7 +40,7 @@ public void testBuildArgument() {
CallArguments callArguments = new CallArguments(
"0x0000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000001","0x10","0.01","0x100",
"","0");
"","0","");
BuildArguments buildArguments = new BuildArguments(callArguments);
Assert.assertEquals(buildArguments.getFrom(),
"0x0000000000000000000000000000000000000000");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class CallArgumentsTest extends BaseTest {
public void init() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has the same problem as BuildArgumentsTest.java:39

callArguments = new CallArguments("0x0000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000001","0x10","0.01","0x100",
"","0");
"","0","");
}

@Test
Expand Down
Loading