Skip to content
Merged
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 @@ -620,6 +620,10 @@ protected static void mergeField(Tokenizer tokenizer,

if (field != null) {
tokenizer.consume(":");
// Match protobuf JsonFormat: a field whose value is null is treated as absent.
if (tokenizer.tryConsume("null")) {
return;
}
boolean array = tokenizer.tryConsume("[");

if (array) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,52 @@ public void testBuildTransactionTransfer() {
}
}

@Test
public void testBuildCreateSmartContractAcceptsNullAbiOutputsOverHttp() {
fullNodeJsonRpcHttpService.start();
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
JsonObject buildArgs = new JsonObject();
buildArgs.addProperty("from", "0xabd4b9367799eaa3197fecb144eb71de1e049abc");
buildArgs.addProperty("data", "608060405234801561001057600080fd5b50");
buildArgs.addProperty("gas", "0x3b9aca00");
buildArgs.addProperty("abi", "[{\"inputs\":[],\"name\":\"test\",\"outputs\":null,"
+ "\"type\":\"function\"}]");
JsonArray params = new JsonArray();
params.add(buildArgs);
JsonObject requestBody = new JsonObject();
requestBody.addProperty("jsonrpc", "2.0");
requestBody.addProperty("method", "buildTransaction");
requestBody.add("params", params);
requestBody.addProperty("id", 1);

HttpPost httpPost = new HttpPost("http://127.0.0.1:"
+ CommonParameter.getInstance().getJsonRpcHttpFullNodePort() + "/jsonrpc");
httpPost.addHeader("Content-Type", "application/json");
httpPost.setEntity(new StringEntity(requestBody.toString()));
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
String resp = EntityUtils.toString(response.getEntity());
JSONObject json = JSON.parseObject(resp);
Assert.assertNull(resp, json.getJSONObject("error"));
JSONObject tx = json.getJSONObject("result").getJSONObject("transaction");
Assert.assertNotNull("transaction must be a JSON object", tx);

JSONArray contracts = tx.getJSONObject("raw_data").getJSONArray("contract");
Assert.assertEquals(1, contracts.size());
JSONObject contract = contracts.getJSONObject(0);
Assert.assertEquals("CreateSmartContract", contract.getString("type"));
JSONObject value = contract.getJSONObject("parameter").getJSONObject("value");
JSONObject abi = value.getJSONObject("new_contract").getJSONObject("abi");
JSONArray entrys = abi.getJSONArray("entrys");
Assert.assertEquals(1, entrys.size());
Assert.assertFalse(entrys.getJSONObject(0).containsKey("outputs"));
}
} catch (Exception e) {
Assert.fail(e.getMessage());
} finally {
fullNodeJsonRpcHttpService.stop();
}
}

@Test
public void testBuildTransactionRejectsDeeplyNestedAbi() {
// A deeply nested ABI must surface as invalid-params (-32602), not as a generic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,31 @@ && addressEquals(((CreateSmartContract) c).getOwnerAddress(),
eq(Protocol.Transaction.Contract.ContractType.CreateSmartContract));
assertTransactionResponse(response);
}

@Test
public void testDeployContractOmitsNullAbiOutputs() throws Exception {
String jsonParam = "{"
+ "\"owner_address\": \"4199357684BC659F5166046B56C95A0E99F1265CD1\","
+ "\"name\": \"TestContract\","
+ "\"abi\": [{\"inputs\":[],\"name\":\"test\",\"outputs\":null,"
+ "\"type\":\"function\"}],"
+ "\"bytecode\": \"608060405234801561001057600080fd5b50\","
+ "\"fee_limit\": 1000000000,"
+ "\"call_value\": 0,"
+ "\"consume_user_resource_percent\": 100,"
+ "\"origin_energy_limit\": 10000000"
+ "}";
MockHttpServletRequest request = postRequest(jsonParam);

MockHttpServletResponse response = newResponse();
servlet.doPost(request, response);
assertEquals(200, response.getStatus());
verify(wallet).createTransactionCapsule(
argThat(c -> c instanceof CreateSmartContract
&& ((CreateSmartContract) c).getNewContract().getAbi().getEntrysCount() == 1
&& ((CreateSmartContract) c).getNewContract().getAbi().getEntrys(0)
.getOutputsCount() == 0),
eq(Protocol.Transaction.Contract.ContractType.CreateSmartContract));
assertTransactionResponse(response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ public void testGetAccountPost() throws Exception {
assertTrue("Should contain address", content.contains("address"));
}

@Test
public void testGetAccountPostNullAddressKeepsDefault() throws Exception {
MockHttpServletRequest request = postRequest("{\"address\": null}");

MockHttpServletResponse response = newResponse();
servlet.doPost(request, response);
assertEquals(200, response.getStatus());
verify(wallet).getAccount(argThat(req -> req != null
&& req.getAddress().equals(ByteString.EMPTY)));
String content = response.getContentAsString();
assertFalse("Should not contain error", content.contains("\"Error\""));
assertTrue("Should contain address", content.contains("address"));
}

@Test
public void testGetAccountGet() throws Exception {
MockHttpServletRequest request = getRequest("address", addrStr);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.tron.core.services.http;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
Expand All @@ -19,6 +20,9 @@
import org.mockito.Mockito;
import org.tron.core.Constant;
import org.tron.protos.Protocol;
import org.tron.protos.contract.ProposalContract.ProposalCreateContract;
import org.tron.protos.contract.SmartContractOuterClass.CreateSmartContract;
import org.tron.protos.contract.SmartContractOuterClass.SmartContract.ABI.Entry;

public class JsonFormatTest {
@After
Expand Down Expand Up @@ -280,6 +284,25 @@ public void testTrailingCommaInKnownRepeatedField() throws Exception {
assertEquals(ByteString.copyFrom(new byte[] {1}), proposal.getApprovals(1));
}

@Test
public void testKnownFieldNullIsSkipped() throws Exception {
Protocol.HelloMessage.Builder hello = Protocol.HelloMessage.newBuilder();
JsonFormat.merge("{\"address\":null}", hello, false);
assertEquals(ByteString.EMPTY, hello.getAddress());

Entry.Builder entry = Entry.newBuilder();
JsonFormat.merge("{\"outputs\":null}", entry, false);
assertEquals(0, entry.getOutputsCount());

CreateSmartContract.Builder contract = CreateSmartContract.newBuilder();
JsonFormat.merge("{\"new_contract\":null}", contract, false);
assertFalse(contract.hasNewContract());

ProposalCreateContract.Builder proposal = ProposalCreateContract.newBuilder();
JsonFormat.merge("{\"parameters\":null}", proposal, false);
assertTrue(proposal.getParametersMap().isEmpty());
}

@Test
public void testKnownRepeatedPrimitiveFieldRejectsNestedArray() {
Protocol.Proposal.Builder builder = Protocol.Proposal.newBuilder();
Expand All @@ -300,6 +323,16 @@ public void testKnownRepeatedMessageFieldRejectsNestedArray() {
assertTrue(e.getMessage().contains("Expected \"{\"."));
}

@Test
public void testKnownRepeatedMessageFieldRejectsNullElement() {
Entry.Builder builder = Entry.newBuilder();

JsonFormat.ParseException e = assertThrows(JsonFormat.ParseException.class,
() -> JsonFormat.merge("{\"outputs\":[null]}", builder, false));

assertTrue(e.getMessage().contains("Expected \"{\"."));
}

@Test
public void testMissingFieldRejectsTrailingCommaInNestedObject() {
Protocol.HelloMessage.Builder builder = Protocol.HelloMessage.newBuilder();
Expand Down
45 changes: 45 additions & 0 deletions framework/src/test/java/org/tron/core/services/http/UtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.tron.json.JSONObject;
import org.tron.protos.Protocol;
import org.tron.protos.Protocol.Transaction;
import org.tron.protos.contract.SmartContractOuterClass.CreateSmartContract;

public class UtilTest extends BaseTest {

Expand Down Expand Up @@ -191,6 +192,50 @@ public void testPackTransaction() {
Assert.assertNotNull(txSignWeight);
}

@Test
public void testPackCreateSmartContractOmitsNullAbiOutputs() throws Exception {
String strTransaction = "{\n"
+ " \"visible\": false,\n"
+ " \"raw_data\": {\n"
+ " \"contract\": [\n"
+ " {\n"
+ " \"parameter\": {\n"
+ " \"value\": {\n"
+ " \"owner_address\":\"41c076305e35aea1fe45a772fcaaab8a36e87bdb55\","
+ " \"new_contract\": {\n"
+ " \"origin_address\":"
+ " \"41c076305e35aea1fe45a772fcaaab8a36e87bdb55\","
+ " \"name\":\"TestContract\","
+ " \"abi\": {\n"
+ " \"entrys\": [\n"
+ " {\"inputs\":[],\"name\":\"test\","
+ " \"outputs\":null,\"type\":\"function\"}\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ " },\n"
+ " \"type_url\":"
+ " \"type.googleapis.com/protocol.CreateSmartContract\"\n"
+ " },\n"
+ " \"type\": \"CreateSmartContract\"\n"
+ " }\n"
+ " ],\n"
+ " \"ref_block_bytes\": \"d8ed\",\n"
+ " \"ref_block_hash\": \"2e066c3259e756f5\",\n"
+ " \"expiration\": 1651906644000,\n"
+ " \"timestamp\": 1651906586162\n"
+ " }\n"
+ "}";

Transaction transaction = Util.packTransaction(strTransaction, false);
Assert.assertNotNull(transaction);
Assert.assertEquals(1, transaction.getRawData().getContractCount());
CreateSmartContract contract = transaction.getRawData().getContract(0)
.getParameter().unpack(CreateSmartContract.class);
Assert.assertEquals(1, contract.getNewContract().getAbi().getEntrysCount());
Assert.assertEquals(0, contract.getNewContract().getAbi().getEntrys(0).getOutputsCount());
}

private Transaction buildTooManySigsTransaction() {
String strTransaction = "{\n"
+ " \"visible\": false,\n"
Expand Down
17 changes: 17 additions & 0 deletions framework/src/test/java/org/tron/json/JsonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static org.junit.Assert.assertTrue;

import com.fasterxml.jackson.core.StreamReadConstraints;
import com.fasterxml.jackson.databind.node.NullNode;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
Expand Down Expand Up @@ -158,6 +159,22 @@ public void testToJSONString() {
assertEquals("\"hi\"", JSON.toJSONString("hi", true));
}

@Test
public void testExplicitNullNodeSerializationIsPreserved() {
JSONObject parsedNull = JSON.parseObject("{\"a\":null,\"b\":1}");
assertTrue(parsedNull.containsKey("a"));
assertNull(parsedNull.get("a"));
assertEquals("{\"a\":null,\"b\":1}", parsedNull.toJSONString());

JSONObject explicitNull = new JSONObject().put("a", NullNode.getInstance()).put("b", 1);
assertTrue(explicitNull.containsKey("a"));
assertEquals("{\"a\":null,\"b\":1}", explicitNull.toJSONString());

explicitNull.put("a", (Object) null);
assertFalse(explicitNull.containsKey("a"));
assertEquals("{\"b\":1}", explicitNull.toJSONString());
}

@Test
public void testJsonObjectGetters() {
JSONObject o = JSON.parseObject(
Expand Down
Loading