Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: reject V1 transactions after milestone #2879

Merged
merged 18 commits into from
Aug 21, 2019
Merged
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
2 changes: 1 addition & 1 deletion __tests__/e2e/lib/config/docker/ark-network-start.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
echo "Starting ark --network-start" >> output.log
CORE_DB_HOST=postgres CORE_DB_DATABASE=ark_testnet CORE_DB_USERNAME=ark ARK_LOG_FILE=ark.log CORE_PATH_CONFIG=./packages/core/bin/config/testnet CORE_PATH_DATA=./packages/core/bin/config/testnet ./packages/core/bin/run core:run --networkStart >> output.log 2> errors.log
CORE_DB_HOST=postgres CORE_DB_DATABASE=ark_testnet CORE_DB_USERNAME=ark ARK_LOG_FILE=ark.log CORE_PATH_CONFIG=./packages/core/bin/config/testnet CORE_PATH_DATA=./packages/core/bin/config/testnet ./packages/core/bin/run core:run --networkStart --env=test >> output.log 2> errors.log
echo "Started ark --network-start" >> output.log
2 changes: 1 addition & 1 deletion __tests__/e2e/lib/config/docker/ark.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
echo "Starting ark" >> output.log
CORE_DB_HOST=postgres CORE_DB_DATABASE=ark_testnet CORE_DB_USERNAME=ark ARK_LOG_FILE=ark.log CORE_PATH_CONFIG=./packages/core/bin/config/testnet CORE_PATH_DATA=./packages/core/bin/config/testnet ./packages/core/bin/run core:run >> output.log 2> errors.log &
CORE_DB_HOST=postgres CORE_DB_DATABASE=ark_testnet CORE_DB_USERNAME=ark ARK_LOG_FILE=ark.log CORE_PATH_CONFIG=./packages/core/bin/config/testnet CORE_PATH_DATA=./packages/core/bin/config/testnet ./packages/core/bin/run core:run --env=test >> output.log 2> errors.log &
echo kill -2 $! > killpid.sh
pwd >> output.log
cat killpid.sh >> output.log
Expand Down
15 changes: 14 additions & 1 deletion __tests__/functional/transaction-forging/__support__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import "jest-extended";
import { Container, Database, State } from "@arkecosystem/core-interfaces";
import { Wallets } from "@arkecosystem/core-state";
import { Identities, Managers, Utils } from "@arkecosystem/crypto";
import { Crypto } from "@arkecosystem/crypto";
import delay from "delay";
import cloneDeep from "lodash.clonedeep";
import { secrets } from "../../../utils/config/testnet/delegates.json";
import { setUpContainer } from "../../../utils/helpers/container";

Expand All @@ -12,6 +14,8 @@ jest.setTimeout(1200000);
let app: Container.IContainer;
export const setUp = async (): Promise<void> => {
try {
process.env.CORE_RESET_DATABASE = "1";

app = await setUpContainer({
include: [
"@arkecosystem/core-event-emitter",
Expand Down Expand Up @@ -57,9 +61,18 @@ export const tearDown = async (): Promise<void> => {

export const snoozeForBlock = async (sleep: number = 0, height: number = 1): Promise<void> => {
const blockTime = Managers.configManager.getMilestone(height).blocktime * 1000;
const remainingTimeInSlot = Crypto.Slots.getTimeInMsUntilNextSlot();
const sleepTime = sleep * 1000;

return delay(blockTime + sleepTime);
return delay(blockTime + remainingTimeInSlot + sleepTime);
};

export const injectMilestone = (index: number, milestone: Record<string, any>): void => {
(Managers.configManager as any).milestones.splice(
index,
0,
Object.assign(cloneDeep(Managers.configManager.getMilestone()), milestone),
);
};

export const getLastHeight = (): number => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe("Transaction Forging - Delegate Registration", () => {
.withPassphraseList(passphrases)
.createOne();

await expect(delegateRegistration.id).toBeRejected();
await expect(delegateRegistration).toBeRejected();
await support.snoozeForBlock(1);
await expect(delegateRegistration.id).not.toBeForged();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ describe("Transaction Forging - Delegate Resignation", () => {
.withPassphrasePair({ passphrase, secondPassphrase })
.createOne();

await expect(transactionsResign.id).toBeRejected();
await expect(transactionsResign).toBeRejected();
await support.snoozeForBlock(1);
await expect(transactionsResign.id).not.toBeForged();
});
Expand Down Expand Up @@ -230,7 +230,7 @@ describe("Transaction Forging - Delegate Resignation", () => {
.withPassphrasePair({ passphrase, secondPassphrase })
.createOne();

await expect(transactionsResign2.id).toBeRejected();
await expect(transactionsResign2).toBeRejected();
await support.snoozeForBlock(1);
await expect(transactionsResign2.id).not.toBeForged();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Identities } from "@arkecosystem/crypto";
import { Identities, Managers } from "@arkecosystem/crypto";
import { TransactionFactory } from "../../helpers/transaction-factory";
import { secrets } from "../../utils/config/testnet/delegates.json";
import * as support from "./__support__";
Expand Down Expand Up @@ -74,4 +74,45 @@ describe("Transaction Forging - Multi Signature Registration", () => {
await support.snoozeForBlock(1);
await expect(multiSignature.id).toBeForged();
});

it("should reject before AIP11 milestone and accept after AIP11 milestone", async () => {
const passphrase = secrets[6];
const initialFunds = TransactionFactory.transfer(Identities.Address.fromPassphrase(passphrase), 100 * 1e8)
.withPassphrase(secrets[0])
.createOne();

await expect(initialFunds).toBeAccepted();
await support.snoozeForBlock(1);
await expect(initialFunds.id).toBeForged();

// Register a multi signature wallet with defaults
const passphrases = [passphrase, secrets[3], secrets[4]];
const participants = [
Identities.PublicKey.fromPassphrase(passphrases[0]),
Identities.PublicKey.fromPassphrase(passphrases[1]),
Identities.PublicKey.fromPassphrase(passphrases[2]),
];

const multiSignature = TransactionFactory.multiSignature(participants, 3)
.withPassphraseList(passphrases)
.withPassphrase(passphrase)
.createOne();

Managers.configManager.getMilestone().aip11 = false;

support.injectMilestone(1, {
height: support.getLastHeight() + 1,
aip11: true,
});

await expect(multiSignature).toBeRejected();
await support.snoozeForBlock(1);
await expect(multiSignature.id).not.toBeForged();

expect(Managers.configManager.getMilestone().aip11).toBeTrue();

await expect(multiSignature).toBeAccepted();
await support.snoozeForBlock(1);
await expect(multiSignature.id).toBeForged();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe("Transaction Forging - Second Signature Registration", () => {
.withPassphraseList(passphrases)
.createOne();

await expect(secondSignature.id).toBeRejected();
await expect(secondSignature).toBeRejected();
await support.snoozeForBlock(1);
await expect(secondSignature.id).not.toBeForged();

Expand Down
46 changes: 36 additions & 10 deletions __tests__/functional/transaction-forging/transfer.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Identities } from "@arkecosystem/crypto";
import { Identities, Managers } from "@arkecosystem/crypto";
import { TransactionFactory } from "../../helpers/transaction-factory";
import { secrets } from "../../utils/config/testnet/delegates.json";
import * as support from "./__support__";
Expand Down Expand Up @@ -124,28 +124,54 @@ describe("Transaction Forging - Transfer", () => {
.withExpiration(support.getLastHeight() + 1)
.createOne();

await expect(transfer.id).toBeRejected();
await expect(transfer2.id).toBeRejected();
await expect(transfer).toBeRejected();
await expect(transfer2).toBeRejected();
await support.snoozeForBlock(1);
await expect(transfer.id).not.toBeForged();
});

it("should broadcast, accept and forge it [Legacy, Without Nonce]", async () => {
const transferWithNonce = TransactionFactory.transfer(Identities.Address.fromPassphrase(passphrase))
it("should accept V1 before AIP11 milestone and reject after AIP11 milestone", async () => {
const transfer = TransactionFactory.transfer(Identities.Address.fromPassphrase(passphrase))
.withPassphrase(secrets[0])
.createOne();

await expect(transferWithNonce).toBeAccepted();
await expect(transfer).toBeAccepted();
await support.snoozeForBlock(1);
await expect(transferWithNonce.id).toBeForged();
await expect(transfer.id).toBeForged();

const transferLegacyWithoutNonce = TransactionFactory.transfer(Identities.Address.fromPassphrase(passphrase))
const transfersLegacyWithoutNonce = TransactionFactory.transfer(Identities.Address.fromPassphrase(passphrase))
.withVersion(1)
.withPassphrase(secrets[0])
.create(2);

Managers.configManager.getMilestone().aip11 = false;

support.injectMilestone(1, {
height: support.getLastHeight() + 1,
aip11: true,
});

// Still accepts 1 height before milestone
await expect(transfersLegacyWithoutNonce[0]).toBeAccepted();
await support.snoozeForBlock(1);
await expect(transfersLegacyWithoutNonce[0].id).toBeForged();

// Now got activated
expect(Managers.configManager.getMilestone().aip11).toBeTrue();

// Rejects V1
await expect(transfersLegacyWithoutNonce[1]).toBeRejected();
await support.snoozeForBlock(1);
await expect(transfersLegacyWithoutNonce[1].id).not.toBeForged();

// and accepts V2
const transferWithNonce = TransactionFactory.transfer(Identities.Address.fromPassphrase(passphrase))
.withPassphrase(secrets[1])
.createOne();

await expect(transferLegacyWithoutNonce).toBeAccepted();
expect(transferWithNonce.version).toBe(2);
await expect(transferWithNonce).toBeAccepted();
await support.snoozeForBlock(1);
await expect(transferLegacyWithoutNonce.id).toBeForged();
await expect(transferWithNonce.id).toBeForged();
});
});
17 changes: 17 additions & 0 deletions __tests__/helpers/block-factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Delegate } from "@arkecosystem/core-forger";
import { Interfaces, Networks, Utils } from "@arkecosystem/crypto";
import { delegates, genesisBlock } from "../utils/fixtures/unitnet";

export class BlockFactory {
public static createDummy(transactions: Interfaces.ITransactionData[] = []): Interfaces.IBlock {
const delegate = new Delegate(delegates[0].passphrase, Networks.unitnet.network);
return delegate.forge(transactions, {
timestamp: 12345689,
previousBlock: {
id: genesisBlock.id,
height: 1,
},
reward: Utils.BigNumber.ZERO,
});
}
}
1 change: 1 addition & 0 deletions __tests__/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./rest-client";
export * from "./transaction-factory";
export * from "./block-factory";
19 changes: 17 additions & 2 deletions __tests__/helpers/transaction-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ export class TransactionFactory {
this.builder.version(this.version);
}

if (this.builder.data.version > 1 && Managers.configManager.getMilestone().aip11) {
if (this.builder.data.version > 1) {
nonce = nonce.plus(1);
this.builder.nonce(nonce);
}
Expand Down Expand Up @@ -317,15 +317,30 @@ export class TransactionFactory {
}
}

const testnet: boolean = ["unitnet", "testnet"].includes(Managers.configManager.get("network.name"));

if (sign) {
const aip11: boolean = Managers.configManager.getMilestone().aip11;
if (this.builder.data.version === 1 && aip11) {
Managers.configManager.getMilestone().aip11 = false;
} else if (testnet) {
Managers.configManager.getMilestone().aip11 = true;
}

this.builder.sign(this.passphrase);

if (this.secondPassphrase) {
this.builder.secondSign(this.secondPassphrase);
}
}

transactions.push(this.builder[method]());
const transaction = this.builder[method]();

if (testnet) {
Managers.configManager.getMilestone().aip11 = true;
}

transactions.push(transaction);
}

return transactions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import "../../../utils";
import { setUp, tearDown } from "../__support__/setup";
import { utils } from "../utils";

import { Address } from "../../../../packages/crypto/src/identities";
import { Identities } from "@arkecosystem/crypto";
import { TransactionFactory } from "../../../helpers/transaction-factory";
import { genesisBlock } from "../../../utils/config/testnet/genesisBlock";
import { delegates } from "../../../utils/fixtures/testnet/delegates";
Expand Down Expand Up @@ -44,7 +44,7 @@ beforeAll(async () => {
wrongType = 3;
version = 1;
senderPublicKey = genesisTransaction.senderPublicKey;
senderAddress = Address.fromPublicKey(genesisTransaction.senderPublicKey, 23);
senderAddress = Identities.Address.fromPublicKey(genesisTransaction.senderPublicKey, 23);
recipientAddress = genesisTransaction.recipientId;
timestamp = genesisTransaction.timestamp;
timestampFrom = timestamp;
Expand Down Expand Up @@ -539,12 +539,10 @@ describe("API 2.0 - Transactions", () => {
const lastAmountPlusFee = +sender.balance - (txNumber - 1) * amountPlusFee;

const transactions = TransactionFactory.transfer(receivers[0].address, amountPlusFee - transferFee)
.withNetwork("testnet")
.withPassphrase(sender.secret)
.create(txNumber - 1);

const lastTransaction = TransactionFactory.transfer(receivers[0].address, lastAmountPlusFee - transferFee)
.withNetwork("testnet")
.withNonce(transactions[transactions.length - 1].nonce)
.withPassphrase(sender.secret)
.create();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import transactionRaw from "./transaction-raw.json";
import transactionTransformed from "./transaction-transformed.json";

Managers.configManager.setFromPreset("testnet");

Managers.configManager.getMilestone().aip11 = false;
const genesisTransaction = Transactions.TransactionFactory.fromData(genesisBlock.transactions[0]);
delete genesisBlock.transactions;

Expand Down
13 changes: 6 additions & 7 deletions __tests__/integration/core-blockchain/blockchain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { Blocks, Crypto, Identities, Interfaces, Utils } from "@arkecosystem/cry
import delay from "delay";
import { Blockchain } from "../../../packages/core-blockchain/src/blockchain";
import { TransactionFactory } from "../../helpers/transaction-factory";
import { genesisBlock as GB } from "../../utils/config/testnet/genesisBlock";
import { blocks101to155 } from "../../utils/fixtures/testnet/blocks101to155";
import { blocks2to100 } from "../../utils/fixtures/testnet/blocks2to100";
import { delegates } from "../../utils/fixtures/testnet/delegates";
Expand All @@ -23,9 +22,8 @@ const resetBlocksInCurrentRound = async () => {
};

const resetToHeight1 = async () => {
const lastBlock = await blockchain.database.getLastBlock();

if (lastBlock) {
if (blockchain.getLastHeight() > 1) {
const lastBlock = await blockchain.database.getLastBlock();
// Make sure the wallet manager has been fed or else revertRound
// cannot determine the previous delegates. This is only necessary, because
// the database is not dropped after the unit tests are done.
Expand Down Expand Up @@ -74,9 +72,10 @@ describe("Blockchain", () => {

blockchain = container.resolvePlugin("blockchain");

// Create the genesis block after the setup has finished or else it uses a potentially
// wrong network config.
genesisBlock = Blocks.BlockFactory.fromData(GB);
genesisBlock = container
.resolvePlugin("state")
.getStore()
.getGenesisBlock();

configManager = container.getConfig();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { app } from "@arkecosystem/core-container";
import { Managers } from "@arkecosystem/crypto";
import { plugin } from "../../../../packages/core-database-postgres/src/plugin";
import { plugin as pluginDatabase } from "../../../../packages/core-database/src/plugin";
import { registerWithContainer, setUpContainer } from "../../../utils/helpers/container";
Expand All @@ -13,6 +14,8 @@ export const setUp = async () => {

process.env.CORE_RESET_DATABASE = "1";

Managers.configManager.getMilestone().aip11 = false;

await registerWithContainer(pluginDatabase);

await registerWithContainer(plugin, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import "jest-extended";

import { app } from "@arkecosystem/core-container";
import { Database, State } from "@arkecosystem/core-interfaces";
import { Blocks, Interfaces } from "@arkecosystem/crypto";
import { Blocks, Interfaces, Managers } from "@arkecosystem/crypto";
import { genesisBlock } from "../../utils/config/testnet/genesisBlock";
import { setUp, tearDown } from "./__support__/setup";

Expand All @@ -12,11 +12,7 @@ let databaseService: Database.IDatabaseService;

beforeAll(async () => {
await setUp();

databaseService = app.resolvePlugin<Database.IDatabaseService>("database");

await databaseService.deleteBlocks([genesisBlock]);
await databaseService.saveBlock(BlockFactory.fromData(genesisBlock));
});

afterAll(async () => {
Expand Down Expand Up @@ -53,7 +49,9 @@ describe("Connection", () => {

describe("getLastBlock", () => {
it("should get the genesis block as last block", async () => {
Managers.configManager.getMilestone().aip11 = false;
await expect(databaseService.getLastBlock()).resolves.toEqual(BlockFactory.fromData(genesisBlock));
Managers.configManager.getMilestone().aip11 = true;
});
});
});
Loading