Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Add new auxiliary functions for CCU #7743

Merged
merged 5 commits into from
Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -34,6 +34,7 @@ import {
CCMApplyContext,
TerminateChainContext,
CreateTerminatedStateAccountContext,
CrossChainUpdateTransactionParams,
} from './types';
import { getCCMSize, getIDAsKeyForStore } from './utils';
import {
Expand All @@ -54,6 +55,10 @@ import { TerminatedOutboxAccount, TerminatedOutboxStore } from './stores/termina
import { ChainAccountUpdatedEvent } from './events/chain_account_updated';
import { TerminatedStateCreatedEvent } from './events/terminated_state_created';
import { BaseInternalMethod } from '../BaseInternalMethod';
import { ChainValidatorsStore } from './stores/chain_validators';
import { MethodContext } from '../../state_machine';
import { certificateSchema } from '../../engine/consensus/certificate_generation/schema';
import { Certificate } from '../../engine/consensus/certificate_generation/types';

export abstract class BaseInteroperabilityInternalMethod extends BaseInternalMethod {
public readonly context: StoreGetter;
Expand Down Expand Up @@ -363,6 +368,40 @@ export abstract class BaseInteroperabilityInternalMethod extends BaseInternalMet
await ccCommand.execute(ccCommandExecuteContext);
}

public async updateValidators(
context: MethodContext,
ccu: CrossChainUpdateTransactionParams,
): Promise<void> {
await this.stores.get(ChainValidatorsStore).updateValidators(context, ccu.sendingChainID, {
activeValidators: ccu.activeValidatorsUpdate,
certificateThreshold: ccu.newCertificateThreshold,
Copy link
Contributor

Choose a reason for hiding this comment

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

For consistency newCertificateThreshold could have been called certificateThresholdUpdate

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this is type definition/schema definition we have now

});
}

public async updateCertificate(
context: MethodContext,
ccu: CrossChainUpdateTransactionParams,
): Promise<void> {
const certificate = codec.decode<Certificate>(certificateSchema, ccu.certificate);
const updatedAccountStore = await this.stores
Copy link
Contributor

Choose a reason for hiding this comment

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

Here are a few observations:

  • stores/chain_account.ts::updateLastCertificate returns chainAccount, while here variable is named as updatedAccountStore

  • updateLastCertificate(...) should only update something, but it's returning something elso + that returned value is fetched from inside of store, but not provided from outside

  • I suggest either of following

const chainAccountStore = await this.stores.get(ChainAccountStore)
const chainAccount = await chainAccountStore.get(context, ccu.sendingChainID)
chainAccount.lastCertificate = {
   height: certificate.height,
   stateRoot: certificate.stateRoot,
   timestamp: certificate.timestamp,
   validatorsHash: certificate.validatorsHash,
};
await chainAccountStore.set(context, ccu.sendingChainID, chainAccount);

OR (preferable if we are updating certificate from multiple places e.g. test case)

const chainAccountStore = await this.stores.get(ChainAccountStore)
const chainAccount = await chainAccountStore.get(context, ccu.sendingChainID)
await chainAccountStore.updateLastCertificate(context, ccu.sendingChainID, chainAccount, certificate);

// stores/chain_account.ts::updateLastCertificate
public async updateLastCertificate(
	context: StoreGetter,
	chainID: Buffer,
	chainAccount: ChainAccount,
	certificate: LastCertificate,
): Promise<void> {
	chainAccount.lastCertificate = {
		height: certificate.height,
		stateRoot: certificate.stateRoot,
		timestamp: certificate.timestamp,
		validatorsHash: certificate.validatorsHash,
	};
	await this.set(context, chainID, chainAccount);
}

.get(ChainAccountStore)
.updateLastCertificate(context, ccu.sendingChainID, certificate);
this.events.get(ChainAccountUpdatedEvent).log(context, ccu.sendingChainID, updatedAccountStore);
}

public async updatePartnerChainOutboxRoot(
context: MethodContext,
ccu: CrossChainUpdateTransactionParams,
): Promise<void> {
await this.stores
.get(ChannelDataStore)
.updatePartnerChainOutboxRoot(
context,
ccu.sendingChainID,
ccu.inboxUpdate.messageWitnessHashes,
);
}

// Different in mainchain and sidechain so to be implemented in each module store separately
public abstract isLive(chainID: Buffer, timestamp?: number): Promise<boolean>;
public abstract sendInternal(sendContext: SendInternalContext): Promise<boolean>;
Expand Down
35 changes: 5 additions & 30 deletions framework/src/modules/interoperability/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { chainValidatorsSchema } from './stores/chain_validators';
import { channelSchema } from './stores/channel_data';
import { outboxRootSchema } from './stores/outbox_root';
import { ownChainAccountSchema } from './stores/own_chain_account';
import { chainIDSchema } from './stores/registered_names';
import { terminatedOutboxSchema } from './stores/terminated_outbox';
import { terminatedStateSchema } from './stores/terminated_state';

Expand Down Expand Up @@ -240,28 +241,17 @@ export const crossChainUpdateTransactionParams = {
inboxUpdate: {
type: 'object',
fieldNumber: 5,
required: ['crossChainMessages', 'messageWitness', 'outboxRootWitness'],
required: ['crossChainMessages', 'messageWitnessHashes', 'outboxRootWitness'],
properties: {
crossChainMessages: {
type: 'array',
fieldNumber: 1,
items: { dataType: 'bytes' },
},
messageWitness: {
type: 'object',
messageWitnessHashes: {
sitetester marked this conversation as resolved.
Show resolved Hide resolved
type: 'array',
fieldNumber: 2,
required: ['partnerChainOutboxSize', 'siblingHashes'],
properties: {
partnerChainOutboxSize: {
dataType: 'uint64',
fieldNumber: 1,
},
siblingHashes: {
type: 'array',
fieldNumber: 2,
items: { dataType: 'bytes' },
},
},
items: { dataType: 'bytes' },
},
outboxRootWitness: {
type: 'object',
Expand Down Expand Up @@ -363,21 +353,6 @@ export const sidechainTerminatedCCMParamsSchema = {
},
};

// https://github.com/LiskHQ/lips/blob/main/proposals/lip-0045.md#registered-names-substore
export const chainIDSchema = {
$id: '/modules/interoperability/chainId',
type: 'object',
required: ['chainID'],
properties: {
chainID: {
dataType: 'bytes',
minLength: CHAIN_ID_LENGTH,
maxLength: CHAIN_ID_LENGTH,
fieldNumber: 1,
},
},
};

export const validatorsHashInputSchema = {
$id: '/modules/interoperability/validatorsHashInput',
type: 'object',
Expand Down
25 changes: 20 additions & 5 deletions framework/src/modules/interoperability/stores/chain_account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@
* Removal or modification of this copyright notice is prohibited.
*/
import { utils } from '@liskhq/lisk-cryptography';
import { ModuleEndpointContext } from '../../../types';
import { BaseStore } from '../../base_store';
import { HASH_LENGTH } from '../constants';
import { MAX_UINT32 } from '../constants';
import { BaseStore, ImmutableStoreGetter, StoreGetter } from '../../base_store';
import { HASH_LENGTH, MAX_UINT32 } from '../constants';

export interface LastCertificate {
height: number;
Expand Down Expand Up @@ -101,7 +99,7 @@ export class ChainAccountStore extends BaseStore<ChainAccount> {
public schema = chainAccountSchema;

public async getAllAccounts(
context: ModuleEndpointContext,
context: ImmutableStoreGetter,
startChainID: Buffer,
): Promise<ChainAccount[]> {
const endBuf = utils.intToBuffer(MAX_UINT32, 4);
Expand All @@ -114,4 +112,21 @@ export class ChainAccountStore extends BaseStore<ChainAccount> {
chainAccounts.map(async chainAccount => this.get(context, chainAccount.key)),
);
}

public async updateLastCertificate(
sitetester marked this conversation as resolved.
Show resolved Hide resolved
context: StoreGetter,
chainID: Buffer,
certificate: LastCertificate,
): Promise<ChainAccount> {
const chainAccount = await this.get(context, chainID);
chainAccount.lastCertificate = {
height: certificate.height,
stateRoot: certificate.stateRoot,
timestamp: certificate.timestamp,
validatorsHash: certificate.validatorsHash,
};
await this.set(context, chainID, chainAccount);

return chainAccount;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* Removal or modification of this copyright notice is prohibited.
*/
import { BaseStore } from '../../base_store';
import { BaseStore, StoreGetter } from '../../base_store';
import { ActiveValidator } from '../types';
import { BLS_PUBLIC_KEY_LENGTH } from '../constants';

Expand Down Expand Up @@ -53,6 +53,47 @@ export const chainValidatorsSchema = {
},
};

// TODO: Fix with #7742 - In order to avoid circular dependency temporally, move to this file
export const updateActiveValidators = (
sitetester marked this conversation as resolved.
Show resolved Hide resolved
activeValidators: ActiveValidator[],
activeValidatorsUpdate: ActiveValidator[],
): ActiveValidator[] => {
for (const updatedValidator of activeValidatorsUpdate) {
const currentValidator = activeValidators.find(v => v.blsKey.equals(updatedValidator.blsKey));
if (currentValidator) {
currentValidator.bftWeight = updatedValidator.bftWeight;
} else {
activeValidators.push(updatedValidator);
activeValidators.sort((v1, v2) => v1.blsKey.compare(v2.blsKey));
Copy link
Contributor

Choose a reason for hiding this comment

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

activeValidators.sort((v1, v2) => v1.blsKey.compare(v2.blsKey));
doesn't need to be inside loop (not good for performance reasons), so it could be just before return activeValidators;

}
}

for (const currentValidator of activeValidators) {
if (currentValidator.bftWeight === BigInt(0)) {
const index = activeValidators.findIndex(v => v.blsKey.equals(currentValidator.blsKey));
activeValidators.splice(index, 1);
}
}
Comment on lines +71 to +76
Copy link
Contributor

Choose a reason for hiding this comment

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

It can also be like this

activeValidators.forEach((currentValidator, index) => {
  if (currentValidator.bftWeight === BigInt(0)) {
    activeValidators.splice(index, 1);
  }
});

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We don't use forEach because it's slow


return activeValidators;
};

export class ChainValidatorsStore extends BaseStore<ChainValidators> {
public schema = chainValidatorsSchema;

public async updateValidators(
context: StoreGetter,
chainID: Buffer,
chainValidators: ChainValidators,
): Promise<void> {
const currentValidators = await this.get(context, chainID);

currentValidators.certificateThreshold = chainValidators.certificateThreshold;
currentValidators.activeValidators = updateActiveValidators(
currentValidators.activeValidators,
chainValidators.activeValidators,
);

await this.set(context, chainID, currentValidators);
}
}
21 changes: 20 additions & 1 deletion framework/src/modules/interoperability/stores/channel_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
*
* Removal or modification of this copyright notice is prohibited.
*/
import { BaseStore } from '../../base_store';
import { regularMerkleTree } from '@liskhq/lisk-tree';
import { BaseStore, StoreGetter } from '../../base_store';
import { HASH_LENGTH } from '../constants';
import { ChannelData } from '../types';
import { TOKEN_ID_LENGTH } from '../../token/constants';
Expand Down Expand Up @@ -73,4 +74,22 @@ export const channelSchema = {

export class ChannelDataStore extends BaseStore<ChannelData> {
public schema = channelSchema;

public async updatePartnerChainOutboxRoot(
context: StoreGetter,
chainID: Buffer,
messageWitnessHashes: Buffer[],
): Promise<void> {
const channel = await this.get(context, chainID);

const outboxRoot = regularMerkleTree.calculateRootFromRightWitness(
channel.inbox.size,
channel.inbox.appendPath,
messageWitnessHashes,
);

channel.partnerChainOutboxRoot = outboxRoot;

await this.set(context, chainID, channel);
}
}
22 changes: 20 additions & 2 deletions framework/src/modules/interoperability/stores/registered_names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,26 @@
* Removal or modification of this copyright notice is prohibited.
*/
import { BaseStore } from '../../base_store';
import { chainIDSchema } from '../schemas';
import { ChainID } from '../types';
import { CHAIN_ID_LENGTH } from '../constants';

// https://github.com/LiskHQ/lips/blob/main/proposals/lip-0045.md#registered-names-substore
export const chainIDSchema = {
$id: '/modules/interoperability/chainId',
type: 'object',
required: ['chainID'],
properties: {
chainID: {
dataType: 'bytes',
minLength: CHAIN_ID_LENGTH,
maxLength: CHAIN_ID_LENGTH,
fieldNumber: 1,
},
},
};

export interface ChainID {
chainID: Buffer;
}

export class RegisteredNamesStore extends BaseStore<ChainID> {
public schema = chainIDSchema;
Expand Down
12 changes: 2 additions & 10 deletions framework/src/modules/interoperability/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Logger } from '../../logger';
import { MethodContext, EventQueue } from '../../state_machine';
import { ImmutableMethodContext, ImmutableSubStore, SubStore } from '../../state_machine/types';
import { OutboxRoot } from './stores/outbox_root';
import { ChainID } from './stores/registered_names';
import { TerminatedOutboxAccount } from './stores/terminated_outbox';
import { TerminatedStateAccount } from './stores/terminated_state';

Expand Down Expand Up @@ -43,19 +44,14 @@ export interface ActiveValidatorJSON {
bftWeight: string;
}

export interface MsgWitness {
partnerChainOutboxSize: bigint;
siblingHashes: Buffer[];
}

export interface OutboxRootWitness {
bitmap: Buffer;
siblingHashes: Buffer[];
}

export interface InboxUpdate {
crossChainMessages: Buffer[];
messageWitness: MsgWitness;
messageWitnessHashes: Buffer[];
outboxRootWitness: OutboxRootWitness;
}

Expand Down Expand Up @@ -335,10 +331,6 @@ export interface ChainValidatorsJSON {
certificateThreshold: string;
}

export interface ChainID {
chainID: Buffer;
}

export interface GenesisInteroperabilityInternalMethod {
outboxRootSubstore: {
storeKey: Buffer;
Expand Down
Loading