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 @@ -246,18 +247,27 @@ private void registerService(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 {
public void executeTransaction(int serviceId, int txId, byte[] arguments,
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
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ private static ServiceInstanceSpec parseInstanceSpec(byte[] instanceSpec) {
* @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(int, int, byte[], Fork, HashCode, PublicKey)
* @see com.exonum.binding.core.transaction.Transaction#execute(TransactionContext)
*/
void executeTransaction(int serviceId, int txId, byte[] arguments,
Expand All @@ -160,13 +160,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);
TransactionContext context = TransactionContext.builder()
.fork(fork)
.txMessageHash(hash)
.authorPk(authorPk)
.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 @@ -16,39 +16,20 @@

package com.exonum.binding.core.transaction;

import static com.google.common.base.Preconditions.checkNotNull;

import com.exonum.binding.common.crypto.PublicKey;
import com.exonum.binding.common.hash.HashCode;
import com.exonum.binding.core.storage.database.Fork;
import com.google.auto.value.AutoValue;

/**
* 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.

*/
final class InternalTransactionContext implements TransactionContext {
private final Fork fork;
private final HashCode hash;
private final PublicKey authorPk;

InternalTransactionContext(Fork fork, HashCode hash, PublicKey authorPk) {
this.fork = checkNotNull(fork);
this.hash = checkNotNull(hash);
this.authorPk = checkNotNull(authorPk);
}

@Override
public Fork getFork() {
return fork;
}

@Override
public HashCode getTransactionMessageHash() {
return hash;
}
@AutoValue
abstract class InternalTransactionContext implements TransactionContext {

@Override
public PublicKey getAuthorPk() {
return authorPk;
public static InternalTransactionContext newInstance(Fork fork, HashCode hash,
PublicKey authorPk, String serviceName,
int serviceId) {
return new AutoValue_InternalTransactionContext(fork, hash, authorPk, serviceName, serviceId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.exonum.binding.core.transaction;

import static com.google.common.base.Preconditions.checkNotNull;

import com.exonum.binding.common.crypto.CryptoFunctions;
import com.exonum.binding.common.crypto.PublicKey;
import com.exonum.binding.common.hash.HashCode;
Expand Down Expand Up @@ -50,6 +52,18 @@ public interface TransactionContext {
*/
PublicKey getAuthorPk();

/**
* Returns the name of the service instance.
*/
String getServiceName();

/**
* Returns the numeric id of the service instance.
*
* @see TransactionMessage#getServiceId()
*/
int getServiceId();

/**
* Returns the builder of the transaction context.
*/
Expand All @@ -64,6 +78,8 @@ final class Builder {
private Fork fork;
private HashCode hash;
private PublicKey authorPk;
private String serviceName;
private Integer serviceId;

/**
* Sets database fork for the context.
Expand All @@ -89,15 +105,30 @@ public Builder authorPk(PublicKey authorPk) {
return this;
}

/**
* Sets service name for the context.
*/
public Builder serviceName(String serviceName) {
this.serviceName = serviceName;
return this;
}

/**
* Sets service id for the context.
*/
public Builder serviceId(int serviceId) {
this.serviceId = serviceId;
return this;
}

/**
* Creates the transaction context instance.
*/
public TransactionContext build() {
return new InternalTransactionContext(fork, hash, authorPk);
return InternalTransactionContext.newInstance(fork, hash, authorPk, serviceName,
checkNotNull(serviceId));
}

private Builder() {
}
private Builder() {}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -368,15 +368,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 @@ -387,14 +391,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)
.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
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ void execute() {
createTestSchemaFactory(fork, schema));

// Execute the transaction
// TODO: use service name and service id when creating TransactionContext
TransactionContext context = newContext(fork);
tx.execute(context);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ void executeClearsQaServiceData() throws CloseFailuresException {
ErrorTx tx = new ErrorTx(0L, errorCode, "Foo");

// Execute the transaction
// TODO: use service name and service id when creating TransactionContext
TransactionContext context = newContext(view);
assertThrows(TransactionExecutionException.class, () -> tx.execute(context));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ void executeClearsQaServiceData() throws CloseFailuresException {
ThrowingTx tx = new ThrowingTx(0L);

// Execute the transaction
// TODO: use service name and service id when creating TransactionContext
TransactionContext context = newContext(view);
IllegalStateException expected = assertThrows(IllegalStateException.class,
() -> tx.execute(context));
Expand Down