Skip to content
Open
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
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ VALIDATORS_CONFIG_JSON = ''
# Consensus mechanism
VITE_FINALITY_WINDOW = 1800 # in seconds
VITE_FINALITY_WINDOW_APPEAL_FAILED_REDUCTION = 0.2 # 20% reduction per appeal failed
VITE_MAX_ROTATIONS = 3
VITE_LEADER_TIMEOUT_FEE = 300
VITE_VALIDATORS_TIMEOUT_FEE = 300
VITE_APPEAL_ROUNDS_FEE = 3
VITE_ROTATIONS_FEE = 2
VITE_FEES_ENABLED = 'true'

# Set the compose profile to 'hardhat' to use the hardhat network
COMPOSE_PROFILES = 'hardhat'
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/Simulator/ConstructorParameters.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import PageSection from '@/components/Simulator/PageSection.vue';
import { ArrowUpTrayIcon } from '@heroicons/vue/16/solid';
import ContractParams from './ContractParams.vue';
import { type ArgData, unfoldArgsData } from './ContractParams';
import type { FeesDistribution } from '@/types';

const props = defineProps<{
leaderOnly: boolean;
consensusMaxRotations: number;
feesDistribution?: FeesDistribution;
}>();

const { contract, contractSchemaQuery, deployContract, isDeploying } =
Expand All @@ -25,7 +26,7 @@ const emit = defineEmits(['deployed-contract']);
const handleDeployContract = async () => {
const args = calldataArguments.value;
const newArgs = unfoldArgsData(args);
await deployContract(newArgs, props.leaderOnly, props.consensusMaxRotations);
await deployContract(newArgs, props.leaderOnly, props.feesDistribution);

emit('deployed-contract');
};
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/Simulator/ContractMethodItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ChevronDownIcon } from '@heroicons/vue/16/solid';
import { useEventTracking, useContractQueries } from '@/hooks';
import { unfoldArgsData, type ArgData } from './ContractParams';
import ContractParams from './ContractParams.vue';
import type { FeesDistribution } from '@/types';

const { callWriteMethod, callReadMethod, contract } = useContractQueries();
const { trackEvent } = useEventTracking();
Expand All @@ -18,7 +19,7 @@ const props = defineProps<{
method: ContractMethod;
methodType: 'read' | 'write';
leaderOnly: boolean;
consensusMaxRotations?: number;
feesDistribution?: FeesDistribution;
}>();

const isExpanded = ref(false);
Expand Down Expand Up @@ -101,7 +102,7 @@ const handleCallWriteMethod = async () => {
await callWriteMethod({
method: props.name,
leaderOnly: props.leaderOnly,
consensusMaxRotations: props.consensusMaxRotations,
feesDistribution: props.feesDistribution,
args: unfoldArgsData({
args: calldataArguments.value.args,
kwargs: calldataArguments.value.kwargs,
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/Simulator/ContractWriteMethods.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import PageSection from '@/components/Simulator/PageSection.vue';
import ContractMethodItem from '@/components/Simulator/ContractMethodItem.vue';
import EmptyListPlaceholder from '@/components/Simulator/EmptyListPlaceholder.vue';
import type { ContractSchema } from 'genlayer-js/types';
import type { FeesDistribution } from '@/types';

const props = defineProps<{
leaderOnly: boolean;
consensusMaxRotations: number;
feesDistribution?: FeesDistribution;
}>();

const { contractAbiQuery } = useContractQueries();
Expand Down Expand Up @@ -42,7 +44,7 @@ const writeMethods = computed(() => {
:method="method[1]"
methodType="write"
:leaderOnly="props.leaderOnly"
:consensusMaxRotations="consensusMaxRotations"
:feesDistribution="props.feesDistribution"
/>

<EmptyListPlaceholder v-if="writeMethods.length === 0">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<script setup lang="ts">
import NumberInput from '@/components/global/inputs/NumberInput.vue';
import type { ConsensusInput } from '@/types/store';

interface Props {
title: string;
inputs: ConsensusInput[];
}

defineProps<Props>();

const isInputValid = (value: number) => {
return !isNaN(value) && Number.isInteger(value) && value >= 0;
};

const handleValueUpdate = (value: number, setter: (value: number) => void) => {
if (isInputValid(value)) {
setter(value);
}
};
</script>

<template>
<div>
<div class="mb-1 text-xs font-semibold opacity-50">{{ title }}</div>
<div
class="overflow-hidden rounded-md border border-gray-300 bg-slate-100 dark:border-gray-800 dark:bg-gray-700"
>
<div
v-for="input in inputs"
:key="input.id"
class="flex items-center justify-between px-2 py-1.5"
>
<div class="truncate text-sm font-medium">{{ input.label }}</div>
<NumberInput
:id="input.id"
:name="input.id"
:min="0"
:step="1"
:model-value="input.value"
@update:model-value="
(val) => handleValueUpdate(Number(val), input.setter)
"
required
:testId="input.testId"
:invalid="!isInputValid(input.value)"
:disabled="false"
class="h-6 w-20"
tiny
/>
</div>
</div>
</div>
</template>
121 changes: 88 additions & 33 deletions frontend/src/components/Simulator/settings/ConsensusSection.vue
Original file line number Diff line number Diff line change
@@ -1,49 +1,104 @@
<script setup lang="ts">
import { ref, computed } from 'vue';
import { computed } from 'vue';
import PageSection from '@/components/Simulator/PageSection.vue';
import FieldError from '@/components/global/fields/FieldError.vue';
import NumberInput from '@/components/global/inputs/NumberInput.vue';
import { useConsensusStore } from '@/stores';
import MoreInfo from '@/components/global/MoreInfo.vue';
import BooleanField from '@/components/global/fields/BooleanField.vue';
import ConsensusInputSection from './ConsensusInputSection.vue';
import type { ConsensusInput } from '@/types/store';

const consensusStore = useConsensusStore();
const maxRotations = computed({
get: () => consensusStore.maxRotations,
set: (newTime) => {
if (isMaxRotationsValid(newTime)) {
consensusStore.setMaxRotations(newTime);
}
},

const feesEnabled = computed({
get: () => consensusStore.feesEnabled,
set: (value) => consensusStore.setFeesEnabled(value),
});

function isMaxRotationsValid(value: number) {
return Number.isInteger(value) && value >= 0;
}
const createConsensusInput = (
storeValue: number,
label: string,
id: string,
setter: (value: number) => void,
): ConsensusInput => {
return {
value: storeValue,
label,
id,
testId: `input-${id}`,
setter,
};
};

const timeUnitsInputs = computed(() => [
createConsensusInput(
consensusStore.leaderTimeoutFee,
'Leader',
'leaderTimeoutFee',
consensusStore.setLeaderTimeoutFee,
),
createConsensusInput(
consensusStore.validatorsTimeoutFee,
'Validators',
'validatorsTimeoutFee',
consensusStore.setValidatorsTimeoutFee,
),
]);

const appealInputs = computed(() => [
createConsensusInput(
consensusStore.appealRoundFee,
'Rounds',
'appealRoundFee',
consensusStore.setAppealRoundFee,
),
]);

const rotationInputs = computed(() =>
consensusStore.rotationsFee.map((fee, index) =>
createConsensusInput(
fee,
`Round ${index + 1}`,
`rotationsFee_${index}`,
(value: number) => consensusStore.setRotationsFee(index, value),
),
),
);
</script>

<template>
<PageSection>
<template #title>Consensus</template>

<div class="p-2">
<div class="flex flex-wrap items-center gap-2">
<label for="maxRotations" class="text-xs">Max Rotations</label>
<NumberInput
id="maxRotations"
name="maxRotations"
:min="0"
:step="1"
v-model.number="maxRotations"
required
testId="input-maxRotations"
:disabled="false"
class="h-6 w-12"
tiny
<template #title>
Consensus
<MoreInfo
text="Configure consensus parameters for transaction processing and validation."
/>
</template>

<div class="space-y-2">
<BooleanField
v-model="feesEnabled"
name="feesEnabled"
label="Enable Fees"
data-testid="toggle-fees"
/>

<template v-if="feesEnabled">
<ConsensusInputSection
title="Time Units Allocation"
:inputs="timeUnitsInputs"
/>

<ConsensusInputSection
title="Appeal Configuration"
:inputs="appealInputs"
/>
</div>

<FieldError v-if="!isMaxRotationsValid"
>Please enter a positive integer.</FieldError
>
<ConsensusInputSection
v-if="rotationInputs.length > 0"
title="Rotations Per Round"
:inputs="rotationInputs"
/>
</template>
</div>
</PageSection>
</template>
12 changes: 6 additions & 6 deletions frontend/src/hooks/useContractQueries.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { watch, ref, computed } from 'vue';
import { useQuery, useQueryClient } from '@tanstack/vue-query';
import type { TransactionItem } from '@/types';
import type { TransactionItem, FeesDistribution } from '@/types';
import {
useContractsStore,
useTransactionsStore,
Expand Down Expand Up @@ -100,7 +100,7 @@ export function useContractQueries() {
kwargs: { [key: string]: CalldataEncodable };
},
leaderOnly: boolean,
consensusMaxRotations: number,
feesDistribution?: FeesDistribution,
) {
isDeploying.value = true;

Expand All @@ -116,7 +116,7 @@ export function useContractQueries() {
code: code_bytes as any as string, // FIXME: code should accept both bytes and string in genlayer-js
args: args.args,
leaderOnly,
consensusMaxRotations,
feesDistribution: feesDistribution,
});

const tx: TransactionItem = {
Expand Down Expand Up @@ -209,15 +209,15 @@ export function useContractQueries() {
method,
args,
leaderOnly,
consensusMaxRotations,
feesDistribution,
}: {
method: string;
args: {
args: CalldataEncodable[];
kwargs: { [key: string]: CalldataEncodable };
};
leaderOnly: boolean;
consensusMaxRotations?: number;
feesDistribution?: FeesDistribution;
}) {
try {
if (!accountsStore.selectedAccount) {
Expand All @@ -230,7 +230,7 @@ export function useContractQueries() {
args: args.args,
value: BigInt(0),
leaderOnly,
consensusMaxRotations,
feesDistribution: feesDistribution,
});

transactionsStore.addTransaction({
Expand Down
Loading
Loading