Skip to content

refactor(core-state): wallet model cleanup #2839

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

Merged
merged 9 commits into from
Jul 24, 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
18 changes: 11 additions & 7 deletions __tests__/functional/transaction-forging/__support__/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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 delay from "delay";
import { secrets } from "../../../utils/config/testnet/delegates.json";
Expand Down Expand Up @@ -29,13 +30,16 @@ export const setUp = async (): Promise<void> => {
await databaseService.reset();
await databaseService.buildWallets();
await databaseService.saveRound(
secrets.map(
secret =>
({
round: 1,
publicKey: Identities.PublicKey.fromPassphrase(secret),
voteBalance: Utils.BigNumber.make("245098000000000"),
} as State.IDelegateWallet),
secrets.map(secret =>
Object.assign(new Wallets.Wallet(Identities.Address.fromPassphrase(secret)), {
publicKey: Identities.PublicKey.fromPassphrase(secret),
attributes: {
delegate: {
voteBalance: Utils.BigNumber.make("245098000000000"),
round: 1,
},
},
}),
),
);
} catch (error) {
Expand Down
5 changes: 3 additions & 2 deletions __tests__/integration/core-api/__support__/setup.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { app } from "@arkecosystem/core-container";
import { Database, State } from "@arkecosystem/core-interfaces";
import { Utils } from "@arkecosystem/crypto";
import delay from "delay";
import { defaults } from "../../../../packages/core-api/src/defaults";
import { plugin } from "../../../../packages/core-api/src/plugin";
Expand Down Expand Up @@ -55,13 +56,13 @@ const calculateRanks = async () => {
const databaseService = app.resolvePlugin<Database.IDatabaseService>("database");

const delegateWallets = Object.values(databaseService.walletManager.allByUsername()).sort(
(a: State.IWallet, b: State.IWallet) => b.voteBalance.comparedTo(a.voteBalance),
(a: State.IWallet, b: State.IWallet) => b.getAttribute<Utils.BigNumber>("delegate.voteBalance").comparedTo(a.getAttribute<Utils.BigNumber>("delegate.voteBalance")),
);

// tslint:disable-next-line: ban
sortBy(delegateWallets, "publicKey").forEach((delegate, i) => {
const wallet = databaseService.walletManager.findByPublicKey(delegate.publicKey);
(wallet as any).rate = i + 1;
wallet.setAttribute("delegate.rank", i + 1);

databaseService.walletManager.reindex(wallet);
});
Expand Down
22 changes: 15 additions & 7 deletions __tests__/integration/core-api/__support__/utils/generate-round.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { Wallets } from "@arkecosystem/core-state";
import { Utils } from "@arkecosystem/crypto";
import { Identities } from "@arkecosystem/crypto/src";

export function generateRound(delegates, round) {
return delegates.map(delegate => ({
round,
publicKey: delegate,
voteBalance: Utils.BigNumber.make("245098000000000"),
}));
}
export const generateRound = (delegates, round) => {
return delegates.map(delegate =>
Object.assign(new Wallets.Wallet(Identities.Address.fromPublicKey(delegate)), {
attributes: {
delegate: {
round,
voteBalance: Utils.BigNumber.make("245098000000000"),
},
},
publicKey: delegate,
}),
);
};
47 changes: 29 additions & 18 deletions __tests__/integration/core-api/handlers/delegates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import { Blocks, Utils } from "@arkecosystem/crypto";
const { BlockFactory } = Blocks;

import { app } from "@arkecosystem/core-container";
import { Database } from "@arkecosystem/core-interfaces";
import { Database, State } from "@arkecosystem/core-interfaces";

const delegate = {
username: "genesis_10",
address: "AFyf2qVpX2JbpKcy29XbusedCpFDeYFX8Q",
publicKey: "02f7acb179ddfddb2e220aa600921574646ac59fd3f1ae6255ada40b9a7fab75fd",
username: "genesis_10",
forgedFees: 50,
forgedRewards: 50,
forgedTotal: 100,
Expand All @@ -30,12 +30,19 @@ beforeAll(async () => {
await setUp();
await calculateRanks();

const wm = app.resolvePlugin("database").walletManager;
const wallet = wm.findByUsername("genesis_10");
wallet.forgedFees = Utils.BigNumber.make(delegate.forgedFees);
wallet.forgedRewards = Utils.BigNumber.make(delegate.forgedRewards);
wallet.producedBlocks = 75;
wallet.voteBalance = Utils.BigNumber.make(delegate.voteBalance);
const wm: State.IWalletManager = app.resolvePlugin("database").walletManager;
const wallet: State.IWallet = wm.findByUsername("genesis_10");

wallet.setAttribute(
"delegate",
Object.assign(wallet.getAttribute("delegate"), {
forgedFees: Utils.BigNumber.make(delegate.forgedFees),
forgedRewards: Utils.BigNumber.make(delegate.forgedRewards),
producedBlocks: 75,
voteBalance: Utils.BigNumber.make(delegate.voteBalance),
}),
);

wm.reindex(wallet);
});

Expand All @@ -58,31 +65,35 @@ describe("API 2.0 - Delegates", () => {
});

it("should GET all the delegates sorted by votes,asc", async () => {
const wm = app.resolvePlugin("database").walletManager;
const wallet = wm.findByUsername("genesis_51");
wallet.voteBalance = Utils.BigNumber.ONE;
const wm: State.IWalletManager = app.resolvePlugin("database").walletManager;
const wallet: State.IWallet = wm.findByUsername("genesis_51");
wallet.setAttribute("delegate.voteBalance", Utils.BigNumber.ONE);
wm.reindex(wallet);

const response = await utils.request("GET", "delegates", { orderBy: "votes:asc" });
expect(response).toBeSuccessfulResponse();
expect(response.data.data).toBeArray();

expect(response.data.data[0].username).toBe(wallet.username);
expect(response.data.data[0].votes).toBe(wallet.voteBalance.toFixed());
expect(response.data.data[0].username).toBe(wallet.getAttribute<string>("delegate.username"));
expect(response.data.data[0].votes).toBe(
wallet.getAttribute<Utils.BigNumber>("delegate.voteBalance").toFixed(),
);
});

it("should GET all the delegates sorted by votes,desc", async () => {
const wm = app.resolvePlugin("database").walletManager;
const wallet = wm.findByUsername("genesis_1");
wallet.voteBalance = Utils.BigNumber.make(12500000000000000);
const wm: State.IWalletManager = app.resolvePlugin("database").walletManager;
const wallet: State.IWallet = wm.findByUsername("genesis_1");
wallet.setAttribute("delegate.voteBalance", Utils.BigNumber.make(12500000000000000));
wm.reindex(wallet);

const response = await utils.request("GET", "delegates", { orderBy: "votes:desc" });
expect(response).toBeSuccessfulResponse();
expect(response.data.data).toBeArray();

expect(response.data.data[0].username).toBe(wallet.username);
expect(response.data.data[0].votes).toBe(wallet.voteBalance.toFixed());
expect(response.data.data[0].username).toBe(wallet.getAttribute("delegate.username"));
expect(response.data.data[0].votes).toBe(
wallet.getAttribute<Utils.BigNumber>("delegate.voteBalance").toFixed(),
);
});

it("should GET all the delegates ordered by descending rank", async () => {
Expand Down
35 changes: 24 additions & 11 deletions __tests__/integration/core-blockchain/blockchain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ const resetToHeight1 = async () => {
const generator = Identities.Address.fromPublicKey(genesisBlock.data.generatorPublicKey);
const genesis = new Wallets.Wallet(generator);
genesis.publicKey = genesisBlock.data.generatorPublicKey;
genesis.username = "genesis";
genesis.setAttribute("delegate", {
username: "genesis",
voteBalance: Utils.BigNumber.ZERO,
producedBlocks: Utils.BigNumber.ZERO,
forgedFees: Utils.BigNumber.ZERO,
forgedRewards: Utils.BigNumber.ZERO,
});

blockchain.database.walletManager.reindex(genesis);

blockchain.state.clear();
Expand Down Expand Up @@ -177,12 +184,12 @@ describe("Blockchain", () => {
// overwritten in afterEach
// FIXME: wallet.lastBlock needs to be properly restored when reverting
for (const forger of forgingDelegates) {
forger.lastBlock = undefined;
forger.forgetAttribute("delegate.lastBlock");
}

expect(forgingDelegates).toEqual(
(blockchain.database as any).forgingDelegates.map(forger => {
forger.lastBlock = undefined;
forger.forgetAttribute("delegate.lastBlock");
return forger;
}),
);
Expand Down Expand Up @@ -234,7 +241,7 @@ describe("Blockchain", () => {
reward: Utils.BigNumber.ZERO,
payloadLength: 32 * transactions.length,
payloadHash: Crypto.HashAlgorithms.sha256(transactionData.ids).toString("hex"),
transactions: transactions,
transactions,
};

return Blocks.BlockFactory.make(data, Identities.Keys.fromPassphrase(generatorKeys.secret));
Expand All @@ -248,7 +255,7 @@ describe("Blockchain", () => {
const recipient = Identities.Address.fromPublicKey(keyPair.publicKey);

let nextForger = await getNextForger();
const initialVoteBalance = nextForger.voteBalance;
const initialVoteBalance: Utils.BigNumber = nextForger.getAttribute("delegate.voteBalance");

// First send funds to new voter wallet
const forgerKeys = delegates.find(wallet => wallet.publicKey === nextForger.publicKey);
Expand All @@ -266,7 +273,9 @@ describe("Blockchain", () => {
// New wallet received funds and vote balance of delegate has been reduced by the same amount,
// since it forged it's own transaction the fees for the transaction have been recovered.
expect(wallet.balance).toEqual(transfer.amount);
expect(walletForger.voteBalance).toEqual(initialVoteBalance.minus(transfer.amount));
expect(walletForger.getAttribute<Utils.BigNumber>("delegate.voteBalance")).toEqual(
initialVoteBalance.minus(transfer.amount),
);

// Now vote with newly created wallet for previous forger.
const vote = TransactionFactory.vote(forgerKeys.publicKey)
Expand All @@ -283,11 +292,13 @@ describe("Blockchain", () => {

// Wallet paid a fee of 1 and the vote has been placed.
expect(wallet.balance).toEqual(Utils.BigNumber.make(124));
expect(wallet.vote).toEqual(forgerKeys.publicKey);
expect(wallet.getAttribute<string>("vote")).toEqual(forgerKeys.publicKey);

// Vote balance of delegate now equals initial vote balance minus 1 for the vote fee
// since it was forged by a different delegate.
expect(walletForger.voteBalance).toEqual(initialVoteBalance.minus(vote.fee));
expect(walletForger.getAttribute<Utils.BigNumber>("delegate.voteBalance")).toEqual(
initialVoteBalance.minus(vote.fee),
);

// Now unvote again
const unvote = TransactionFactory.unvote(forgerKeys.publicKey)
Expand All @@ -304,17 +315,19 @@ describe("Blockchain", () => {

// Wallet paid a fee of 1 and no longer voted a delegate
expect(wallet.balance).toEqual(Utils.BigNumber.make(123));
expect(wallet.vote).toBeUndefined();
expect(wallet.hasVoted()).toBeFalse();

// Vote balance of delegate now equals initial vote balance minus the amount sent to the voter wallet.
expect(walletForger.voteBalance).toEqual(initialVoteBalance.minus(transfer.amount));
expect(walletForger.getAttribute<Utils.BigNumber>("delegate.voteBalance")).toEqual(
initialVoteBalance.minus(transfer.amount),
);

// Now rewind 3 blocks back to the initial state
await blockchain.removeBlocks(3);

// Wallet is now a cold wallet and the initial vote balance has been restored.
expect(wallet.balance).toEqual(Utils.BigNumber.ZERO);
expect(walletForger.voteBalance).toEqual(initialVoteBalance);
expect(walletForger.getAttribute<Utils.BigNumber>("delegate.voteBalance")).toEqual(initialVoteBalance);
});
});

Expand Down
4 changes: 2 additions & 2 deletions __tests__/integration/core-transaction-pool/processor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,8 @@ describe("Transaction Guard", () => {
const wallet1 = transactionPool.walletManager.findByPublicKey(wallets[14].keys.publicKey);
const wallet2 = transactionPool.walletManager.findByPublicKey(wallets[15].keys.publicKey);

expect(wallet1.username).toBe(undefined);
expect(wallet2.username).toBe(undefined);
expect(wallet1.isDelegate()).toBeFalse();
expect(wallet2.isDelegate()).toBeFalse();
});

it("should not validate a transaction if a second signature registration for the same wallet exists in the pool", async () => {
Expand Down
2 changes: 1 addition & 1 deletion __tests__/unit/core-blockchain/mocks/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export const database = {
restoredDatabaseIntegrity: true,

walletManager: {
findByPublicKey: pubKey => "username",
findByPublicKey: pubKey => ({ getAttribute: () => "username" }),
revertBlock: () => undefined,
},

Expand Down
25 changes: 18 additions & 7 deletions __tests__/unit/core-database/database-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,12 @@ describe("Database Service", () => {
for (const transaction of genesisBlock.transactions) {
if (transaction.type === TransactionTypes.DelegateRegistration) {
const wallet = walletManager.findByPublicKey(transaction.data.senderPublicKey);
wallet.username = Transactions.TransactionFactory.fromBytes(
transaction.serialized,
).data.asset.delegate.username;
wallet.setAttribute("delegate", {
voteBalance: Utils.BigNumber.ONE,
username: Transactions.TransactionFactory.fromBytes(
transaction.serialized,
).data.asset.delegate.username,
});
wallet.address = Identities.Address.fromPublicKey(transaction.data.senderPublicKey);
walletManager.reindex(wallet);
}
Expand All @@ -222,6 +225,13 @@ describe("Database Service", () => {
const sender = new Wallet(keys.address);
sender.publicKey = keys.publicKey;
sender.balance = Utils.BigNumber.make(1e12);
sender.setAttribute("delegate", {
voteBalance: Utils.BigNumber.ZERO,
forgedFees: Utils.BigNumber.ZERO,
forgedRewards: Utils.BigNumber.ZERO,
producedBlocks: Utils.BigNumber.ZERO,
});

walletManager.reindex(sender);

// Apply 51 blocks, where each increases the vote balance of a delegate to
Expand All @@ -238,7 +248,7 @@ describe("Database Service", () => {
.build();

// Vote for delegate
walletManager.findByPublicKey(voterKeys.publicKey).vote = delegatesRound2[i].publicKey;
walletManager.findByPublicKey(voterKeys.publicKey).setAttribute("vote", delegatesRound2[i].publicKey);

const block = BlockFactory.make(
{
Expand Down Expand Up @@ -266,8 +276,9 @@ describe("Database Service", () => {
// The delegates from round 2 are now reversed in rank in round 3.
const roundInfo2 = roundCalculator.calculateRound(initialHeight + 51);
const delegatesRound3 = walletManager.loadActiveDelegateList(roundInfo2);

for (let i = 0; i < delegatesRound3.length; i++) {
expect(delegatesRound3[i].rate).toBe(i + 1);
expect(delegatesRound3[i].getAttribute<number>("delegate.rank")).toBe(i + 1);
expect(delegatesRound3[i].publicKey).toBe(delegatesRound2[delegatesRound3.length - i - 1].publicKey);
}

Expand All @@ -284,10 +295,10 @@ describe("Database Service", () => {
});

// Finally recalculate the round 2 list and compare against the original list
const restoredDelegatesRound2 = await (databaseService as any).calcPreviousActiveDelegates(roundInfo2);
const restoredDelegatesRound2: State.IWallet[] = await (databaseService as any).calcPreviousActiveDelegates(roundInfo2);

for (let i = 0; i < restoredDelegatesRound2.length; i++) {
expect(restoredDelegatesRound2[i].rate).toBe(i + 1);
expect(restoredDelegatesRound2[i].getAttribute<number>("delegate.rank")).toBe(i + 1);
expect(restoredDelegatesRound2[i].publicKey).toBe(delegatesRound2[i].publicKey);
}

Expand Down
Loading