Skip to content

Commit

Permalink
chore: upgrade fuel-core to 0.19.0 (#1085)
Browse files Browse the repository at this point in the history
* chore: upgrade fuel core version to 0.19.0

* feat: update fuel core schema

* test: add coin input to tests and alter concensus param test for new shape

* feat: add maxGasPerPredicate to gql consensus params operation

* feat: add maxGasPerPredicate to chain config

* chore: revert commit for code explanation and lint

* chore: remove redundant test param

* feat: implement estimate predicates

* chore: revert predicate test changes

* chore: reformat gql schema

* chore: linting

* feat: include predicateGasUsed in transaction encoding

* feat: alter max gas per predicate tx param

* feat: add predicate gas used to transaction inputs

* feat: remove logs and add docs to predicate gas used call

* feat: alter calculate for contract and predicate root

* feat: update gql shema

* feat: conditionally call estimate predicates

* chore: linting

* test: update input coder expectations

* feat: remove fund transaction property from get contract calls

* test: update hasher expectation

* test: update signer expectation

* test: remove redundant testcase from auth testing

* test: update transaction coder assertion

* chore: linting

* chore: linting

* chore: linting

* test: add witness index in provider call test

* test: remove redundant test case from storage contract test

* feat: update message coder to include predicate gas used

* chore: linting

* feat: add predicate truthy check to check predicate function on transaction request

* chore: force rebuild

* chore: changeset

* chore: force rebuild

* feat: hash keys for SMT

* feat: hash smt keys at entrypoint to calc storage root

* chore: linting

* chore: linting

---------

Co-authored-by: danielbate <--global>
  • Loading branch information
danielbate authored Jul 12, 2023
1 parent 882ee97 commit 6bf970a
Show file tree
Hide file tree
Showing 21 changed files with 161 additions and 84 deletions.
13 changes: 13 additions & 0 deletions .changeset/nine-pets-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"docs": minor
"@fuel-ts/contract": minor
"@fuel-ts/fuel-core": minor
"@fuel-ts/predicate": minor
"@fuel-ts/program": minor
"@fuel-ts/providers": minor
"@fuel-ts/testcases": minor
"@fuel-ts/transactions": minor
"@fuel-ts/versions": minor
---

Update fuel core version to 0.19.0
1 change: 1 addition & 0 deletions .fuel-core/configs/chainConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@
"max_storage_slots": 255,
"max_predicate_length": 1048576,
"max_predicate_data_length": 1048576,
"max_gas_per_predicate": 100000000,
"gas_price_factor": 1000000000,
"gas_per_byte": 4,
"max_message_data_length": 1048576
Expand Down
18 changes: 6 additions & 12 deletions packages/contract/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { calcRoot, SparseMerkleTree } from '@fuel-ts/merkle';
import type { StorageSlot } from '@fuel-ts/transactions';

export const getContractRoot = (bytecode: BytesLike): string => {
const chunkSize = 8;
const chunkSize = 16 * 1024;
const chunks: Uint8Array[] = [];
const bytes = arrayify(bytecode);

Expand All @@ -15,25 +15,19 @@ export const getContractRoot = (bytecode: BytesLike): string => {
chunks.push(chunk);
}

const totalBytes = chunks.reduce((sum, chunk) => chunk.byteLength + sum, 0);
const lastChunk = chunks[chunks.length - 1];
const isDivisibleBy16 = totalBytes % 16 === 0;
const remainingBytes = chunkSize - lastChunk.length;
if (!isDivisibleBy16) {
const nearestMultiple = Math.ceil(remainingBytes / 8) * 8;
const paddedChunkLength = lastChunk.length + nearestMultiple;
const paddedChunk = new Uint8Array(paddedChunkLength).fill(0);
paddedChunk.set(lastChunk, 0);
chunks[chunks.length - 1] = paddedChunk;
}
const remainingBytes = bytes.length % chunkSize;
const paddedChunkLength = remainingBytes + ((8 - (remainingBytes % 8)) % 8);
const newChunk = lastChunk.slice(0, paddedChunkLength);
chunks[chunks.length - 1] = newChunk;

return calcRoot(chunks.map((c) => hexlify(c)));
};

export const getContractStorageRoot = (storageSlots: StorageSlot[]): string => {
const tree = new SparseMerkleTree();

storageSlots.forEach(({ key, value }) => tree.update(key, value));
storageSlots.forEach(({ key, value }) => tree.update(sha256(key), value));

return tree.root;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/fuel-core/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.18.3
0.19.0
14 changes: 1 addition & 13 deletions packages/fuel-gauge/src/auth-testing.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { generateTestWallet } from '@fuel-ts/wallet/test-utils';
import fs from 'fs';
import type { Contract, WalletUnlocked } from 'fuels';
import {
AssertFailedRevertError,
RevertError,
ContractFactory,
NativeAssetId,
Provider,
} from 'fuels';
import { AssertFailedRevertError, ContractFactory, NativeAssetId, Provider } from 'fuels';
import path from 'path';

import FactoryAbi from '../test-projects/auth_testing_contract/out/debug/auth_testing_contract-abi.json';
Expand Down Expand Up @@ -44,12 +38,6 @@ describe('Auth Testing', () => {
expect(value).toBeTruthy();
});

it('can check_msg_sender [with correct id, using get]', async () => {
await expect(
contractInstance.functions.check_msg_sender({ value: wallet.address.toB256() }).get()
).rejects.toThrow(RevertError);
});

it('can check_msg_sender [with incorrect id]', async () => {
await expect(
contractInstance.functions
Expand Down
13 changes: 0 additions & 13 deletions packages/fuel-gauge/src/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,19 +563,6 @@ describe('Contract', () => {
expect(JSON.stringify(value)).toEqual(JSON.stringify([bn(100), bn(200)]));
});

it('get should not fundTransaction', async () => {
const contract = await setupContract();

await expect(
contract.functions
.return_context_amount()
.callParams({
forward: [200, AltToken],
})
.get()
).rejects.toThrow();
});

it('Parse TX to JSON and parse back to TX', async () => {
const contract = await setupContract();

Expand Down
14 changes: 1 addition & 13 deletions packages/fuel-gauge/src/storage-test-contract.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { generateTestWallet } from '@fuel-ts/wallet/test-utils';
import { readFileSync } from 'fs';
import { toHex, Provider, Contract, ContractFactory, NativeAssetId } from 'fuels';
import { toHex, Provider, ContractFactory, NativeAssetId } from 'fuels';
import { join } from 'path';

import abi from '../test-projects/storage-test-contract/out/debug/storage-test-abi.json';
Expand Down Expand Up @@ -36,16 +36,4 @@ describe('StorageTestContract', () => {
const { value: count } = await contract.functions.counter().get();
expect(count.toHex()).toEqual(toHex(1337));
});

it('can access counter value with only provider (no wallet)', async () => {
const contract = await setup();

// Call contract
await contract.functions.initialize_counter(1300).call();

const provider = new Provider('http://127.0.0.1:4000/graphql');
const providerContract = new Contract(contract.id, contract.interface, provider);
const { value } = await providerContract.functions.counter().get();
expect(value.toHex()).toEqual(toHex(1300));
});
});
1 change: 0 additions & 1 deletion packages/merkle/src/sparse/sparseMerkleTree.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ describe('Sparse Merkle Tree', () => {
const newData = toHex(43, 32);
const n = 100;

/// Roots from Go implementation
const rootAfterLeaves = '0xdc0537167454509d360e0807b673b0bdfde730dd8ce944a43e397e3a16ac322b';
const rootAfterUpdateExisting =
'0x846fb76ccb1cd6f3a2802c658a6ab1befd658e25ff7a81e955e14da50fa77c02';
Expand Down
19 changes: 6 additions & 13 deletions packages/predicate/src/utils/getContractRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { hash, uint64ToBytesBE } from '@fuel-ts/hasher';
import { calcRoot } from '@fuel-ts/merkle';

export const getContractRoot = (bytecode: BytesLike, chainId: number): string => {
const chunkSize = 8;
const chunkSize = 16 * 1024;
const chunks: Uint8Array[] = [];
const bytes = arrayify(bytecode);

Expand All @@ -14,19 +14,12 @@ export const getContractRoot = (bytecode: BytesLike, chainId: number): string =>
chunks.push(chunk);
}

const totalBytes = chunks.reduce((sum, chunk) => chunk.byteLength + sum, 0);
const lastChunk = chunks[chunks.length - 1];
const isDivisibleBy16 = totalBytes % 16 === 0;
const remainingBytes = chunkSize - lastChunk.length;
if (!isDivisibleBy16) {
const nearestMultiple = Math.ceil(remainingBytes / 8) * 8;
const paddedChunkLength = lastChunk.length + nearestMultiple;
const paddedChunk = new Uint8Array(paddedChunkLength).fill(0);
paddedChunk.set(lastChunk, 0);
chunks[chunks.length - 1] = paddedChunk;
}

const chainIdBytes = uint64ToBytesBE(chainId);
const lastChunk = chunks[chunks.length - 1];
const remainingBytes = bytes.length % chunkSize;
const paddedChunkLength = remainingBytes + ((8 - (remainingBytes % 8)) % 8);
const newChunk = lastChunk.slice(0, paddedChunkLength);
chunks[chunks.length - 1] = newChunk;
const codeRoot = calcRoot(chunks.map((c) => hexlify(c)));

const contractRoot = hash(concat(['0x4655454C', chainIdBytes, codeRoot]));
Expand Down
3 changes: 2 additions & 1 deletion packages/program/src/functions/base-invocation-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,11 @@ export class BaseInvocationScope<TReturn = any> {
* Under the hood it uses the `dryRun` method but don't fund the transaction
* with coins by default, for emulating executions with forward coins use `dryRun`
* or pass the options.fundTransaction as true
*
* TODO: refactor out use of get() in place of call()
*/
async get<T = TReturn>(options?: CallOptions): Promise<InvocationCallResult<T>> {
return this.dryRun<T>({
fundTransaction: false,
...options,
});
}
Expand Down
17 changes: 16 additions & 1 deletion packages/providers/fuel-core-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ type ConsensusParameters {
maxStorageSlots: U64!
maxPredicateLength: U64!
maxPredicateDataLength: U64!
maxGasPerPredicate: U64!
gasPriceFactor: U64!
gasPerByte: U64!
maxMessageDataLength: U64!
Expand Down Expand Up @@ -366,6 +367,7 @@ type InputCoin {
txPointer: TxPointer!
witnessIndex: Int!
maturity: U32!
predicateGasUsed: U64!
predicate: HexString!
predicateData: HexString!
}
Expand All @@ -384,6 +386,7 @@ type InputMessage {
amount: U64!
nonce: Nonce!
witnessIndex: Int!
predicateGasUsed: U64!
data: HexString!
predicate: HexString!
predicateData: HexString!
Expand Down Expand Up @@ -465,7 +468,9 @@ type Mutation {
dryRun(tx: HexString!, utxoValidation: Boolean): [Receipt!]!

"""
Submits transaction to the txpool
Submits transaction to the `TxPool`.
Returns submitted transaction if the transaction is included in the `TxPool` without problems.
"""
submit(tx: HexString!): Transaction!

Expand Down Expand Up @@ -585,6 +590,11 @@ type Query {
before: String
): TransactionConnection!

"""
Estimate the predicate gas for the provided transaction
"""
estimatePredicates(tx: HexString!): Transaction!

"""
Returns true when the GraphQL API is serving requests.
"""
Expand Down Expand Up @@ -775,6 +785,11 @@ type Subscription {
"""
id: TransactionId!
): TransactionStatus!

"""
Submits transaction to the `TxPool` and await either confirmation or failure.
"""
submitAndAwait(tx: HexString!): TransactionStatus!
}

type SuccessStatus {
Expand Down
7 changes: 7 additions & 0 deletions packages/providers/src/operations.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ fragment consensusParametersFragment on ConsensusParameters {
maxStorageSlots
maxPredicateLength
maxPredicateDataLength
maxGasPerPredicate
gasPriceFactor
gasPerByte
maxMessageDataLength
Expand Down Expand Up @@ -232,6 +233,12 @@ query getTransactionsByOwner(
}
}

query estimatePredicates($encodedTransaction: HexString!) {
estimatePredicates(tx: $encodedTransaction) {
...transactionFragment
}
}

query getBlock($blockId: BlockId, $blockHeight: U64) {
block(id: $blockId, height: $blockHeight) {
...blockFragment
Expand Down
50 changes: 43 additions & 7 deletions packages/providers/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,26 @@ import { MAX_GAS_PER_TX } from '@fuel-ts/transactions/configs';
import { GraphQLClient } from 'graphql-request';
import cloneDeep from 'lodash.clonedeep';

import { getSdk as getOperationsSdk } from './__generated__/operations';
import type {
GqlChainInfoFragmentFragment,
GqlGetBlocksQueryVariables,
GqlGetInfoQuery,
GqlReceiptFragmentFragment,
} from './__generated__/operations';
import { getSdk as getOperationsSdk } from './__generated__/operations';
import type { Coin } from './coin';
import type { CoinQuantity, CoinQuantityLike } from './coin-quantity';
import { coinQuantityfy } from './coin-quantity';
import { MemoryCache } from './memory-cache';
import type { Message, MessageCoin, MessageProof } from './message';
import type { ExcludeResourcesOption, Resource } from './resource';
import { transactionRequestify } from './transaction-request';
import type {
TransactionRequestLike,
TransactionRequest,
TransactionRequestInput,
CoinTransactionRequestInput,
} from './transaction-request';
import { transactionRequestify, ScriptTransactionRequest } from './transaction-request';
import type { TransactionResultReceipt } from './transaction-response/transaction-response';
import { TransactionResponse } from './transaction-response/transaction-response';
import { calculateTransactionFee, fromUnixToTai64, getReceiptsWithMissingData } from './utils';
Expand Down Expand Up @@ -84,6 +85,7 @@ export type ChainInfo = {
maxStorageSlots: BN;
maxPredicateLength: BN;
maxPredicateDataLength: BN;
maxGasPerPredicate: BN;
gasPriceFactor: BN;
gasPerByte: BN;
maxMessageDataLength: BN;
Expand Down Expand Up @@ -153,6 +155,7 @@ const processGqlChain = (chain: GqlChainInfoFragmentFragment): ChainInfo => {
maxStorageSlots: bn(consensusParameters.maxStorageSlots),
maxPredicateLength: bn(consensusParameters.maxPredicateLength),
maxPredicateDataLength: bn(consensusParameters.maxPredicateDataLength),
maxGasPerPredicate: bn(consensusParameters.maxGasPerPredicate),
gasPriceFactor: bn(consensusParameters.gasPriceFactor),
gasPerByte: bn(consensusParameters.gasPerByte),
maxMessageDataLength: bn(consensusParameters.maxMessageDataLength),
Expand Down Expand Up @@ -370,6 +373,33 @@ export default class Provider {
};
}

/**
* Verifies whether enough gas is available to complete transaction
*/
async estimatePredicates(transactionRequest: TransactionRequest): Promise<TransactionRequest> {
const encodedTransaction = hexlify(transactionRequest.toTransactionBytes());
const response = await this.operations.estimatePredicates({
encodedTransaction,
});

const estimatedTransaction = transactionRequest;
const [decodedTransaction] = new TransactionCoder().decode(
arrayify(response.estimatePredicates.rawPayload),
0
);

if (decodedTransaction.inputs) {
decodedTransaction.inputs.forEach((input, index) => {
if (input.type === InputType.Coin && input.predicate) {
(<CoinTransactionRequestInput>estimatedTransaction.inputs[index]).predicateGasUsed =
input.predicateGasUsed;
}
});
}

return estimatedTransaction;
}

/**
* Will dryRun a transaction and check for missing dependencies.
*
Expand All @@ -389,8 +419,11 @@ export default class Provider {
return;
}

const encodedTransaction = transactionRequest.hasPredicateInput()
? hexlify((await this.estimatePredicates(transactionRequest)).toTransactionBytes())
: hexlify(transactionRequest.toTransactionBytes());

do {
const encodedTransaction = hexlify(transactionRequest.toTransactionBytes());
const { dryRun: gqlReceipts } = await this.operations.dryRun({
encodedTransaction,
utxoValidation: false,
Expand All @@ -406,11 +439,14 @@ export default class Provider {
return;
}

transactionRequest.addVariableOutputs(missingOutputVariableCount);
if (transactionRequest instanceof ScriptTransactionRequest) {
transactionRequest.addVariableOutputs(missingOutputVariableCount);

missingOutputContractIds.forEach(({ contractId }) =>
transactionRequest.addContractInputAndOutput(Address.fromString(contractId))
);
}

missingOutputContractIds.forEach(({ contractId }) =>
transactionRequest.addContractInputAndOutput(Address.fromString(contractId))
);
tries += 1;
} while (tries < MAX_RETRIES);
}
Expand Down
Loading

0 comments on commit 6bf970a

Please sign in to comment.