Skip to content

Commit

Permalink
txbuilder time
Browse files Browse the repository at this point in the history
  • Loading branch information
michele-nuzzi committed Apr 26, 2023
1 parent 156dd7f commit d2b0b7a
Show file tree
Hide file tree
Showing 7 changed files with 313 additions and 12 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@harmoniclabs/plu-ts",
"version": "0.3.1",
"version": "0.3.2-dev0",
"description": "An embedded DSL for Cardano smart contracts creation coupled with a library for Cardano transactions, all in Typescript",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
28 changes: 28 additions & 0 deletions src/offchain/ledger/Address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,34 @@ export class Address
readonly stakeCreds?: StakeCredentials
readonly type!: AddressType;

static mainnet(
paymentCreds: PaymentCredentials,
stakeCreds?: StakeCredentials,
type?: AddressType
): Address
{
return new Address(
"mainnet",
paymentCreds,
stakeCreds,
type
);
}

static testnet(
paymentCreds: PaymentCredentials,
stakeCreds?: StakeCredentials,
type?: AddressType
): Address
{
return new Address(
"testnet",
paymentCreds,
stakeCreds,
type
);
}

constructor(
network: NetworkT,
paymentCreds: PaymentCredentials,
Expand Down
7 changes: 7 additions & 0 deletions src/offchain/tx/body/output/TxOutRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,11 @@ export class TxOutRef
};
}

static get fake(): TxOutRef
{
return new TxOutRef({
id: "ff".repeat(32),
index: 0
});
}
}
43 changes: 34 additions & 9 deletions src/offchain/tx/builder/TxBuilder/TxBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ObjectUtils from "../../../../utils/ObjectUtils";
import type { NetworkT } from "../../../ledger/Network";
import { costModelV1ToFakeV2, costModelsToCborObj, costModelsToLanguageViewCbor, defaultV1Costs, defaultV2Costs, isCostModelsV1, isCostModelsV2, toCostModelV2 } from "../../../ledger/CostModels";
import { txBuildOutToTxOut } from "../txBuild/ITxBuildOutput";
import { CanBeUInteger, forceBigUInt } from "../../../../types/ints/Integer";
import { CanBeUInteger, canBeUInteger, forceBigUInt, unsafeForceUInt } from "../../../../types/ints/Integer";
import { Script, ScriptType } from "../../../script/Script";
import { ProtocolParamters, isPartialProtocolParameters } from "../../../ledger/protocol/ProtocolParameters";
import { getTxInfos } from "../toOnChain/getTxInfos";
Expand Down Expand Up @@ -46,6 +46,7 @@ import { keepRelevant } from "./keepRelevant";
import { GenesisInfos, isGenesisInfos } from "./GenesisInfos";
import { IProvider } from "./IProvider";
import { TxBuilderRunner } from "./TxBuilderRunner";
import { POSIXToSlot } from "../toOnChain";

type ScriptLike = {
hash: string,
Expand Down Expand Up @@ -94,7 +95,7 @@ export class TxBuilder
constructor(
network: NetworkT,
protocolParamters: Readonly<ProtocolParamters>,
geneisInfos?: GenesisInfos
genesisInfos?: GenesisInfos
)
{
let _genesisInfos: GenesisInfos | undefined = undefined;
Expand All @@ -103,14 +104,22 @@ export class TxBuilder

_genesisInfos = ObjectUtils.freezeAll( genInfos );
}
_setGenesisInfos( geneisInfos! );
Object.defineProperty(
this, "genesisInfos",
_setGenesisInfos( genesisInfos! );
Object.defineProperties(
this,
{
get: () => _genesisInfos,
set: _setGenesisInfos,
enumerable: true,
configurable: false
genesisInfos: {
get: () => _genesisInfos,
set: _setGenesisInfos,
enumerable: true,
configurable: false
},
setGenesisInfos: {
value: _setGenesisInfos,
writable: false,
enumerable: true,
configurable: false
}
}
);

Expand Down Expand Up @@ -868,6 +877,22 @@ function initTxBuild(
}
).toBuffer();

invalidBefore = invalidBefore === undef ? undef : forceBigUInt( invalidBefore );

if( invalidAfter !== undef )
{
if( invalidBefore === undef ) invalidBefore = 0;
}

if(
canBeUInteger( invalidBefore ) &&
canBeUInteger( invalidAfter )
)
{
if( invalidBefore >= invalidAfter )
throw new BasePlutsError("invalid validity interval; invalidAfter: " + invalidAfter.toString() + "; was smaller (previous poin in time) than invalidBefore:" + invalidBefore.toString() );
}

const dummyTx = new Tx({
body: {
inputs: _inputs,
Expand Down
240 changes: 240 additions & 0 deletions src/offchain/tx/builder/__tests__/TxBuilder.build.time.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import { Address, Value, defaultProtocolParameters } from "../../../ledger"
import { TxOut, TxOutRef, UTxO } from "../../body"
import { TxBuilder } from "../TxBuilder"
import { PScriptContext, compile, data, pfn, pmakeUnit, unit } from "../../../../onchain";
import { Script } from "../../../script/Script";
import { PaymentCredentials } from "../../../credentials";
import { DataI } from "../../../../types/Data";


describe("build time", () => {

const txBuilder = new TxBuilder(
"mainnet",
defaultProtocolParameters
);

const txBuilderWithGenesis = new TxBuilder(
"mainnet",
defaultProtocolParameters,
{
slotLengthInMilliseconds: 1000,
systemStartPOSIX: (Math.round( Date.now() / 1e3 ) * 1e3) - 1e6
}
);

test("only invalid before results in validityStart", () => {

const tx = txBuilder.buildSync({
inputs: [
{
utxo: new UTxO({
utxoRef: TxOutRef.fake,
resolved: {
address: Address.fake,
value: Value.lovelaces(2_000_000)
}
})
}
],
invalidBefore: 42,
changeAddress: Address.fake
});

expect( tx.body.validityIntervalStart )
.not.toBe( undefined );

expect( tx.body.validityIntervalStart )
.toBe( 42n );

});

test("only invalid after results in validityStart=0 and ttl", () => {

const tx = txBuilder.buildSync({
inputs: [
{
utxo: new UTxO({
utxoRef: TxOutRef.fake,
resolved: {
address: Address.fake,
value: Value.lovelaces(2_000_000)
}
})
}
],
invalidAfter: 42,
changeAddress: Address.fake
});

expect( tx.body.validityIntervalStart )
.not.toBe( undefined );

expect( tx.body.ttl )
.not.toBe( undefined );

});

test("invalid before and invalid after", () => {

const tx = txBuilder.buildSync({
inputs: [
{
utxo: new UTxO({
utxoRef: TxOutRef.fake,
resolved: {
address: Address.fake,
value: Value.lovelaces(2_000_000)
}
})
}
],
invalidBefore: 42,
invalidAfter: 69,
changeAddress: Address.fake
});

expect( tx.body.validityIntervalStart )
.not.toBe( undefined );

expect( tx.body.validityIntervalStart )
.toBe( 42n );

expect( tx.body.ttl )
.not.toBe( undefined );

expect( tx.body.ttl )
.toBe( 69n - 42n );

});

test("invalid before > invalid after; fails", () => {

expect( () => txBuilder.buildSync({
inputs: [
{
utxo: new UTxO({
utxoRef: TxOutRef.fake,
resolved: {
address: Address.fake,
value: Value.lovelaces(2_000_000)
}
})
}
],
invalidBefore: 69,
invalidAfter: 42,
changeAddress: Address.fake
})).toThrow();

});

const simpleScript = new Script(
"PlutusScriptV2",
compile(
pfn([ data, data, PScriptContext.type ], unit )( ( d, r, c ) => pmakeUnit() )
)
);

const simpleScriptAddress = Address.mainnet(
PaymentCredentials.script(
simpleScript.hash
)
);

test("tx builder with time and script but no genesis fails", () => {

expect( () => txBuilder.buildSync({
inputs: [
{
utxo: new UTxO({
utxoRef: TxOutRef.fake,
resolved: {
address: simpleScriptAddress,
value: Value.lovelaces(2_000_000),
datum: new DataI( 0 )
}
}),
inputScript: {
script: simpleScript,
datum: "inline",
redeemer: new DataI( 0 )
}
}
],
invalidBefore: 42,
invalidAfter: 69,
changeAddress: Address.fake
})).toThrow();

});

test("tx builder with time and script and genesis is ok", () => {

expect( () => txBuilderWithGenesis.buildSync({
inputs: [
{
utxo: new UTxO({
utxoRef: TxOutRef.fake,
resolved: {
address: simpleScriptAddress,
value: Value.lovelaces(2_000_000),
datum: new DataI( 0 )
}
}),
inputScript: {
script: simpleScript,
datum: "inline",
redeemer: new DataI( 0 )
}
}
],
invalidBefore: 42,
invalidAfter: 69,
changeAddress: Address.fake
})).not.toThrow();

});

test("genesis can be setted", () => {

const myTxBuilder = new TxBuilder(
"mainnet",
defaultProtocolParameters
);

const doStuff = () => myTxBuilder.buildSync({
inputs: [
{
utxo: new UTxO({
utxoRef: TxOutRef.fake,
resolved: {
address: simpleScriptAddress,
value: Value.lovelaces(2_000_000),
datum: new DataI( 0 )
}
}),
inputScript: {
script: simpleScript,
datum: "inline",
redeemer: new DataI( 0 )
}
}
],
invalidBefore: 42,
invalidAfter: 69,
changeAddress: Address.fake
})

expect( doStuff ).toThrow();

myTxBuilder.setGenesisInfos({
slotLengthInMilliseconds: 1000,
systemStartPOSIX: (Math.round( Date.now() / 1e3 ) * 1e3) - 1e6
});

expect( doStuff ).not.toThrow();

});

})
2 changes: 1 addition & 1 deletion src/onchain/pluts/Script/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from "./compile"
export * from "./makeScript"
export * from "./blueprint";
// export * from "./blueprint";
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@
"**/*.test.ts",
"jest_cache",
"tsc-out",
"src/offchain/tx/builder/buildWorker.ts"
"src/offchain/tx/builder/buildWorker.ts",
"src/onchain/pluts/Script/blueprint"
],
"tsc-alias": {
"verbose": false,
Expand Down

0 comments on commit d2b0b7a

Please sign in to comment.