Skip to content

Commit

Permalink
Refactor operations to eliminate duplicate code between EVM versions (#…
Browse files Browse the repository at this point in the history
…7000)

Signed-off-by: Michael Tinker <[email protected]>
  • Loading branch information
tinker-michaelj authored and povolev15 committed Jun 27, 2023
1 parent 6c52a71 commit d75dd6e
Show file tree
Hide file tree
Showing 98 changed files with 6,734 additions and 197 deletions.
12 changes: 6 additions & 6 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
*/

plugins {
id("com.hedera.hashgraph.aggregate-reports")
id("com.hedera.hashgraph.spotless-conventions")
id("com.hedera.hashgraph.spotless-kotlin-conventions")
id("com.hedera.hashgraph.dependency-analysis")
id("com.hedera.hashgraph.aggregate-reports")
id("com.hedera.hashgraph.spotless-conventions")
id("com.hedera.hashgraph.spotless-kotlin-conventions")
id("com.hedera.hashgraph.dependency-analysis")
}

repositories {
mavenCentral()
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
mavenCentral()
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2023 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.hedera.node.app.spi.meta.bni;

import com.hedera.hapi.node.base.ContractID;
import com.hedera.hapi.node.base.Key;
import com.hedera.pbj.runtime.io.buffer.Bytes;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Objects;

/**
* A {@link VerificationStrategy} that verifies signatures from a single active contract. This is the
* verification strategy used within the EVM to check receiver signature requirements.
*/
public class ActiveContractVerificationStrategy implements VerificationStrategy {
private final long activeNumber;
private final Bytes activeAddress;
private final boolean requiresDelegatePermission;

public ActiveContractVerificationStrategy(
final long activeNumber, @NonNull final Bytes activeAddress, final boolean requiresDelegatePermission) {
this.activeNumber = activeNumber;
this.activeAddress = Objects.requireNonNull(activeAddress);
this.requiresDelegatePermission = requiresDelegatePermission;
}

/**
* {@inheritDoc}
*/
@Override
public Decision maybeVerifySignature(@NonNull final Key key, @NonNull final KeyRole keyRole) {
final var keyKind = key.key().kind();
if (keyKind == Key.KeyOneOfType.CONTRACT_ID) {
if (requiresDelegatePermission) {
return Decision.INVALID;
} else {
return decisionFor(key.contractIDOrThrow());
}
} else if (keyKind == Key.KeyOneOfType.DELEGATABLE_CONTRACT_ID) {
return decisionFor(key.delegatableContractIdOrThrow());
} else {
return Decision.DELEGATE_TO_CRYPTOGRAPHIC_VERIFICATION;
}
}

public long getActiveNumber() {
return activeNumber;
}

public Bytes getActiveAddress() {
return activeAddress;
}

public boolean requiresDelegatePermission() {
return requiresDelegatePermission;
}

private Decision decisionFor(@NonNull final ContractID authorizedId) {
if (authorizedId.hasContractNum() && authorizedId.contractNumOrThrow() == activeNumber) {
return Decision.VALID;
} else if (authorizedId.hasEvmAddress() && activeAddress.equals(authorizedId.evmAddress())) {
return Decision.VALID;
} else {
return Decision.INVALID;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,25 @@ TokenRelationship getRelationshipAndExternalizeResult(
* @param strategy the {@link VerificationStrategy} to use
* @return the result of the transfer attempt
*/
ResponseCodeEnum transferValue(
ResponseCodeEnum transferWithReceiverSigCheck(
long amount, long fromEntityNumber, long toEntityNumber, @NonNull VerificationStrategy strategy);

/**
* Collects the given {@code amount} of fees from the given {@code fromEntityNumber}.
*
* @param fromEntityNumber the number of the entity to collect fees from
* @param amount the amount of fees to collect
*/
void collectFee(long fromEntityNumber, long amount);

/**
* Refunds the given {@code amount} of fees from the given {@code fromEntityNumber}.
*
* @param fromEntityNumber the number of the entity to refund fees to
* @param amount the amount of fees to collect
*/
void refundFee(long fromEntityNumber, long amount);

/**
* Links the given {@code evmAddress} to the given {@code entityNumber} as an alias.
*
Expand Down Expand Up @@ -296,4 +312,14 @@ ResponseCodeEnum transferValue(
*/
@Nullable
Nft getNft(@NonNull UniqueTokenId id);

// --- (SECTION V) Miscellaneous methods
/**
* Tracks the deletion of a contract and the beneficiary that should receive any staking awards otherwise
* earned by the deleted contract.
*
* @param deletedNumber the number of the deleted contract
* @param beneficiaryNumber the number of the beneficiary
*/
void trackDeletion(long deletedNumber, long beneficiaryNumber);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*
* <p>Because it possible for the {@code tokenTransfer()} system contract to need to amend
* its dispatched transaction based on the results of signature verifications, the strategy
* also has the option to return an amended transaction body when an .
* also has the option to return an amended transaction body when this occurs.
*/
public interface VerificationStrategy {
enum Decision {
Expand Down Expand Up @@ -74,6 +74,8 @@ enum KeyRole {
* @return an amended CryptoTransfer, or null if no amendment is necessary
*/
@Nullable
CryptoTransferTransactionBody maybeAmendTransfer(
@NonNull CryptoTransferTransactionBody transfer, List<Long> invalidSignerNumbers);
default CryptoTransferTransactionBody maybeAmendTransfer(
@NonNull CryptoTransferTransactionBody transfer, List<Long> invalidSignerNumbers) {
throw new UnsupportedOperationException("Default verification strategy does not amend transfers");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright (C) 2023 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.hedera.node.app.spi.meta.bni;

import static org.junit.jupiter.api.Assertions.*;

import com.hedera.hapi.node.base.ContractID;
import com.hedera.hapi.node.base.Key;
import com.hedera.hapi.node.token.CryptoTransferTransactionBody;
import com.hedera.pbj.runtime.io.buffer.Bytes;
import java.util.List;
import org.junit.jupiter.api.Test;

class ActiveContractVerificationStrategyTest {
private static final long ACTIVE_NUMBER = 1234L;
private static final long SOME_OTHER_NUMBER = 2345L;
private static final Bytes ACTIVE_ADDRESS = Bytes.fromHex("1234");
private static final Bytes OTHER_ADDRESS = Bytes.fromHex("abcd");

private static final Key ACTIVE_ID_KEY = Key.newBuilder()
.contractID(ContractID.newBuilder().contractNum(ACTIVE_NUMBER))
.build();
private static final Key DELEGATABLE_ACTIVE_ID_KEY = Key.newBuilder()
.delegatableContractId(ContractID.newBuilder().contractNum(ACTIVE_NUMBER))
.build();
private static final Key INACTIVE_ID_KEY = Key.newBuilder()
.contractID(ContractID.newBuilder().contractNum(SOME_OTHER_NUMBER))
.build();
private static final Key DELEGATABLE_INACTIVE_ID_KEY = Key.newBuilder()
.delegatableContractId(ContractID.newBuilder().contractNum(SOME_OTHER_NUMBER))
.build();
private static final Key ACTIVE_ADDRESS_KEY = Key.newBuilder()
.contractID(ContractID.newBuilder().evmAddress(ACTIVE_ADDRESS))
.build();
private static final Key DELEGATABLE_ACTIVE_ADDRESS_KEY = Key.newBuilder()
.delegatableContractId(ContractID.newBuilder().evmAddress(ACTIVE_ADDRESS))
.build();
private static final Key INACTIVE_ADDRESS_KEY = Key.newBuilder()
.contractID(ContractID.newBuilder().evmAddress(OTHER_ADDRESS))
.build();
private static final Key DELEGATABLE_INACTIVE_ADDRESS_KEY = Key.newBuilder()
.delegatableContractId(ContractID.newBuilder().evmAddress(OTHER_ADDRESS))
.build();
private static final Key CRYPTO_KEY = Key.newBuilder()
.ed25519(Bytes.fromHex("1234567812345678123456781234567812345678123456781234567812345678"))
.build();

@Test
void validatesKeysAsExpectedWhenDelegatePermissionNotRequired() {
final var subject = new ActiveContractVerificationStrategy(ACTIVE_NUMBER, ACTIVE_ADDRESS, false);

assertEquals(
VerificationStrategy.Decision.VALID,
subject.maybeVerifySignature(ACTIVE_ID_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.VALID,
subject.maybeVerifySignature(ACTIVE_ADDRESS_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(INACTIVE_ID_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(INACTIVE_ADDRESS_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.VALID,
subject.maybeVerifySignature(DELEGATABLE_ACTIVE_ID_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.VALID,
subject.maybeVerifySignature(DELEGATABLE_ACTIVE_ADDRESS_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(DELEGATABLE_INACTIVE_ID_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(DELEGATABLE_INACTIVE_ADDRESS_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.DELEGATE_TO_CRYPTOGRAPHIC_VERIFICATION,
subject.maybeVerifySignature(CRYPTO_KEY, VerificationStrategy.KeyRole.OTHER));
}

@Test
void validatesKeysAsExpectedWhenDelegatePermissionRequired() {
final var subject = new ActiveContractVerificationStrategy(ACTIVE_NUMBER, ACTIVE_ADDRESS, true);

assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(ACTIVE_ID_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(ACTIVE_ADDRESS_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(INACTIVE_ID_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(INACTIVE_ADDRESS_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.VALID,
subject.maybeVerifySignature(DELEGATABLE_ACTIVE_ID_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.VALID,
subject.maybeVerifySignature(DELEGATABLE_ACTIVE_ADDRESS_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(DELEGATABLE_INACTIVE_ID_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.INVALID,
subject.maybeVerifySignature(DELEGATABLE_INACTIVE_ADDRESS_KEY, VerificationStrategy.KeyRole.OTHER));
assertEquals(
VerificationStrategy.Decision.DELEGATE_TO_CRYPTOGRAPHIC_VERIFICATION,
subject.maybeVerifySignature(CRYPTO_KEY, VerificationStrategy.KeyRole.OTHER));
}

@Test
void doesNotSupportAmendingTransfer() {
final var subject = new ActiveContractVerificationStrategy(ACTIVE_NUMBER, ACTIVE_ADDRESS, true);

assertThrows(
UnsupportedOperationException.class,
() -> subject.maybeAmendTransfer(CryptoTransferTransactionBody.DEFAULT, List.of()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import com.hedera.node.app.service.consensus.ConsensusService;
import com.hedera.node.app.service.consensus.impl.ConsensusServiceImpl;
import com.hedera.node.app.service.contract.ContractService;
import com.hedera.node.app.service.contract.impl.ContractServiceImpl;
import com.hedera.node.app.service.contract.impl.state.ContractSchema;
import com.hedera.node.app.service.file.FileService;
import com.hedera.node.app.service.file.impl.FileServiceImpl;
import com.hedera.node.app.service.mono.context.StateChildrenProvider;
Expand Down Expand Up @@ -762,8 +762,8 @@ public VirtualMapLike<VirtualBlobKey, VirtualBlobValue> storage() {
public VirtualMapLike<ContractKey, IterableContractValue> contractStorage() {
return VirtualMapLikeAdapter.unwrapping(
(StateMetadata<ContractKey, IterableContractValue>)
services.get(ContractService.NAME).get(ContractServiceImpl.STORAGE_KEY),
getChild(findNodeIndex(ContractService.NAME, ContractServiceImpl.STORAGE_KEY)));
services.get(ContractService.NAME).get(ContractSchema.STORAGE_KEY),
getChild(findNodeIndex(ContractService.NAME, ContractSchema.STORAGE_KEY)));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public Address targetContractAddress(final MessageFrame frame) {
return alias;
}

private static Bytes32 keccak256(final Bytes input) {
public static Bytes32 keccak256(final Bytes input) {
return Bytes32.wrap(keccak256DigestOf(input.toArrayUnsafe()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.hedera.node.app.service.mono.context.properties.GlobalDynamicProperties;
import com.hedera.node.app.service.mono.fees.HbarCentExchange;
import com.hedera.node.app.service.mono.fees.calculation.UsagePricesProvider;
import edu.umd.cs.findbugs.annotations.Nullable;
import javax.inject.Inject;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.datatypes.Wei;
Expand Down Expand Up @@ -127,7 +128,7 @@ public long extCodeHashOperationGasCost() {
}

@Override
public long selfDestructOperationGasCost(final Account recipient, final Wei inheritance) {
public long selfDestructOperationGasCost(@Nullable final Account recipient, final Wei inheritance) {
// Frontier gas cost
return 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ dependencies {
}
}

val generatedSources = file("build/generated/sources/annotationProcessor/java/main")

java.sourceSets["main"].java.srcDir(generatedSources)

// TODO module-info.java in 'test'
// https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin/issues/900
dependencyAnalysis.issues {
Expand Down
Loading

0 comments on commit d75dd6e

Please sign in to comment.