Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static com.google.common.base.Preconditions.checkState;
import static java.util.stream.Collectors.toList;

import com.exonum.binding.common.crypto.PublicKey;
import com.exonum.binding.common.hash.HashCode;
import com.exonum.binding.core.runtime.ServiceRuntimeProtos.ServiceRuntimeStateHashes;
import com.exonum.binding.core.runtime.ServiceRuntimeProtos.ServiceStateHashes;
Expand Down Expand Up @@ -260,18 +261,27 @@ private void unregisterService(ServiceWrapper service) {

/**
* Executes a transaction belonging to the given service.
*
* @param serviceId the numeric identifier of the service instance to which the transaction
* belongs
* @param txId the transaction type identifier
* @param arguments the serialized transaction arguments
* @param context the transaction execution context
* @param fork a native fork object
* @param txMessageHash the hash of the transaction message
* @param authorPublicKey the public key of the transaction author
*/
public void executeTransaction(Integer serviceId, int txId, byte[] arguments,
TransactionContext context) throws TransactionExecutionException {
Fork fork, HashCode txMessageHash, PublicKey authorPublicKey)
throws TransactionExecutionException {
synchronized (lock) {
ServiceWrapper service = getServiceById(serviceId);

String serviceName = service.getName();
TransactionContext context = TransactionContext.builder()
.fork(fork)
.txMessageHash(txMessageHash)
.authorPk(authorPublicKey)
.serviceName(serviceName)
.serviceId(serviceId)
.build();
try {
service.executeTransaction(txId, arguments, context);
} catch (Exception e) {
Expand Down Expand Up @@ -437,17 +447,6 @@ private void logApiMountEvent(ServiceWrapper service, String serviceApiPath, Rou
);
}

/**
* Get service name by its id.
*
* @throws IllegalArgumentException if there is no service with such id
*/
public String getServiceNameById(Integer serviceId) {
synchronized (lock) {
return getServiceById(serviceId).getName();
}
}

private ServiceWrapper getServiceById(Integer serviceId) {
checkService(serviceId);
return servicesById.get(serviceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ void stopService(int id) {
* @param txMessageHash the hash of the transaction message
* @param authorPublicKey the public key of the transaction author
* @throws TransactionExecutionException if the transaction execution failed
* @see ServiceRuntime#executeTransaction(Integer, int, byte[], TransactionContext)
* @see ServiceRuntime#executeTransaction(Integer, int, byte[], TransactionContext, Fork,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @see ServiceRuntime#executeTransaction(Integer, int, byte[], TransactionContext, Fork,
* @see ServiceRuntime#executeTransaction(Integer, int, byte[], Fork,

* HashCode, PublicKey)
* @see com.exonum.binding.core.transaction.Transaction#execute(TransactionContext)
*/
void executeTransaction(int serviceId, int txId, byte[] arguments,
Expand All @@ -157,16 +158,8 @@ void executeTransaction(int serviceId, int txId, byte[] arguments,
Fork fork = viewFactory.createFork(forkNativeHandle, cleaner);
HashCode hash = HashCode.fromBytes(txMessageHash);
PublicKey authorPk = PublicKey.fromBytes(authorPublicKey);
String serviceName = serviceRuntime.getServiceNameById(serviceId);
TransactionContext context = TransactionContext.builder()
.fork(fork)
.txMessageHash(hash)
.authorPk(authorPk)
.serviceName(serviceName)
.serviceId(serviceId)
.build();

serviceRuntime.executeTransaction(serviceId, txId, arguments, context);

serviceRuntime.executeTransaction(serviceId, txId, arguments, fork, hash, authorPk);
} catch (CloseFailuresException e) {
handleCloseFailure(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.exonum.binding.common.crypto.PublicKey;
import com.exonum.binding.common.hash.HashCode;
import com.exonum.binding.core.storage.database.Fork;
import java.util.Objects;

/**
* Default implementation of the transaction context.
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to use @AutoValue here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, added @AutoValue.

Expand Down Expand Up @@ -65,4 +66,25 @@ public String getServiceName() {
public Integer getServiceId() {
return serviceId;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
InternalTransactionContext that = (InternalTransactionContext) o;
return serviceId == that.serviceId
&& Objects.equals(fork, that.fork)
&& Objects.equals(hash, that.hash)
&& Objects.equals(authorPk, that.authorPk)
&& Objects.equals(serviceName, that.serviceName);
}

@Override
public int hashCode() {
return Objects.hash(fork, hash, authorPk, serviceName, serviceId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -320,17 +320,19 @@ void executeTransaction() throws Exception {
Cleaner cleaner = new Cleaner()) {
int txId = 1;
byte[] arguments = bytes(127);
TransactionContext context = TransactionContext.builder()
.fork(database.createFork(cleaner))
Fork fork = database.createFork(cleaner);
TransactionContext expectedContext = TransactionContext.builder()
.fork(fork)
.txMessageHash(TEST_HASH)
.authorPk(TEST_PUBLIC_KEY)
.serviceName(TEST_NAME)
.serviceId(TEST_ID)
.build();

serviceRuntime.executeTransaction(TEST_ID, txId, arguments, context);
serviceRuntime.executeTransaction(TEST_ID, txId, arguments, fork, TEST_HASH,
TEST_PUBLIC_KEY);

verify(serviceWrapper).executeTransaction(txId, arguments, context);
verify(serviceWrapper).executeTransaction(txId, arguments, expectedContext);
}
}

Expand All @@ -341,16 +343,10 @@ void executeTransactionUnknownService() throws Exception {
int serviceId = TEST_ID + 1;
int txId = 1;
byte[] arguments = bytes(127);
TransactionContext context = TransactionContext.builder()
.fork(database.createFork(cleaner))
.txMessageHash(TEST_HASH)
.authorPk(TEST_PUBLIC_KEY)
.serviceName(TEST_NAME)
.serviceId(TEST_ID)
.build();

Exception e = assertThrows(IllegalArgumentException.class,
() -> serviceRuntime.executeTransaction(serviceId, txId, arguments, context));
() -> serviceRuntime.executeTransaction(serviceId, txId, arguments,
database.createFork(cleaner), TEST_HASH, TEST_PUBLIC_KEY));

assertThat(e).hasMessageContaining(String.valueOf(serviceId));
}
Expand Down Expand Up @@ -442,21 +438,6 @@ void connectServiceApisSingleService() {
verify(serviceWrapper).createPublicApiHandlers(node, serviceRouter);
verify(server).mountSubRouter(API_ROOT_PATH + "/" + serviceApiPath, serviceRouter);
}

@Test
void getServiceNameByInstance() {
assertThat(serviceRuntime.getServiceNameById(TEST_ID)).isEqualTo(TEST_NAME);
}

@Test
void getServiceNameByInstanceUnknownServiceId() {
Integer invalidServiceId = TEST_ID + 1;
Exception e = assertThrows(IllegalArgumentException.class,
() -> serviceRuntime.getServiceNameById(invalidServiceId));
String expectedMessage =
String.format("No service with id=%s in the Java runtime", invalidServiceId);
assertThat(e).hasMessageContaining(expectedMessage);
}
}

private static byte[] anyConfiguration() {
Expand Down