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

feat: Implement Delegate Resignation (AIP11) #2538

Merged
merged 28 commits into from
May 10, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8d9eacf
feat: complete the delegate resignation transaction type
vasild May 7, 2019
9eb4aba
Merge remote-tracking branch 'ArkEcosystem/core/develop' into feat/de…
vasild May 8, 2019
90e4b83
feat: introduce a wallet flag indicating whether a delegate resigned
vasild May 8, 2019
f334cad
Merge remote-tracking branch 'ArkEcosystem/core/develop' into feat/de…
vasild May 8, 2019
b58f7dc
feat: do not allow voting for a resigned delegate
vasild May 8, 2019
7c9040a
Merge branch 'develop' into feat/delegate-resignation
faustbrian May 9, 2019
bcfce03
fix: revert all unnecessary changes
faustbrian May 9, 2019
758981e
fix(core-transactions): apply resigned flag on boot to delegates
faustbrian May 9, 2019
ef434f9
test: adjust expectations of failing tests
faustbrian May 9, 2019
e19bfd5
test: add handler and functional tests for delegate resignation
faustbrian May 9, 2019
68aef6f
test(crypto): enable AIP11 for delegate resignation signing
faustbrian May 9, 2019
d55644b
test(functional): add delegate resignation forging tests
faustbrian May 9, 2019
119d03e
test(functional): register a delegate before resigning with 2nd signa…
faustbrian May 9, 2019
231169d
chore: remove `delegates` argument from buildDelegateRanking()
vasild May 9, 2019
4df1f59
chore: set delegate resignation version to 2
vasild May 9, 2019
fc0f65c
test: update and enable DelegateResignationTransaction unit tests
vasild May 9, 2019
6c8f73c
test: generate a proper tx to test delegate resignation
vasild May 9, 2019
049e826
Merge remote-tracking branch 'ArkEcosystem/core/develop' into feat/de…
vasild May 9, 2019
fb137fa
test: use unitnet for unit tests
vasild May 9, 2019
4d9ffda
fix: throw if a delegate already resigned
faustbrian May 10, 2019
4200d0d
fix: variable name collision
faustbrian May 10, 2019
9031872
Merge remote-tracking branch 'ArkEcosystem/core/develop' into feat/de…
vasild May 10, 2019
9cf775b
Merge branch 'develop' into feat/delegate-resignation
faustbrian May 10, 2019
0fd5b3c
Merge branch 'develop' into feat/delegate-resignation
faustbrian May 10, 2019
14d57b9
test: adjust tests after 1bea3ff4e
vasild May 10, 2019
17c6487
Merge branch 'develop' into feat/delegate-resignation
faustbrian May 10, 2019
eda7137
Apply suggestions from code review
faustbrian May 10, 2019
805c3d8
Update __tests__/functional/transaction-forging/delegate-resignation.…
faustbrian May 10, 2019
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
4 changes: 4 additions & 0 deletions __tests__/helpers/transaction-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export class TransactionFactory {
return new TransactionFactory(Transactions.BuilderFactory.delegateRegistration().usernameAsset(username));
}

public static delegateResignation(): TransactionFactory {
return new TransactionFactory(Transactions.BuilderFactory.delegateResignation());
}

public static vote(publicKey?: string): TransactionFactory {
return new TransactionFactory(
Transactions.BuilderFactory.vote().votesAsset([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import { Enums } from "@arkecosystem/crypto";
const { TransactionTypes } = Enums;

describe(".toBeDelegateType", () => {
test("passes when given a valid transaction", () => {
test("passes when given a delegate transaction", () => {
expect({
type: TransactionTypes.DelegateRegistration,
}).toBeDelegateType();

expect({
type: TransactionTypes.DelegateResignation,
}).toBeDelegateType();
});

test("fails when given an invalid transaction", () => {
test("fails when given a non-delegate transaction", () => {
expect(expect({ type: "invalid" }).toBeDelegateType).toThrowError(
"Expected value to be a valid DELEGATE transaction.",
);
Expand Down
17 changes: 17 additions & 0 deletions __tests__/unit/core-state/wallets/wallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,23 @@ describe("Models - Wallet", () => {
]);
});

it("should return correct audit data for delegate resignation type", () => {
const transaction = TransactionFactory.delegateResignation()
.withNetwork("devnet")
.withPassphrase("super secret passphrase")
.create()[0];
const audit = testWallet.auditApply(transaction);

expect(audit).toEqual([
{
"Remaining amount": +walletInit.balance.minus(transaction.amount).minus(transaction.fee),
},
{ "Signature validation": true },
{ "Current username": undefined },
{ "New username": undefined },
]);
});

it("should return correct audit data for vote type", () => {
const transaction = TransactionFactory.vote(
"02337316a26d8d49ec27059bd0589c49ba474029c3627715380f4df83fb431aece",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Enums } from "@arkecosystem/crypto";

const { DelegateRegistration } = Enums.TransactionTypes;
const { TransactionTypes } = Enums;

export {};

Expand All @@ -17,7 +17,8 @@ expect.extend({
toBeDelegateType: received => {
return {
message: () => "Expected value to be a valid DELEGATE transaction.",
pass: received.type === DelegateRegistration,
pass: received.type === TransactionTypes.DelegateRegistration ||
received.type === TransactionTypes.DelegateResignation,
faustbrian marked this conversation as resolved.
Show resolved Hide resolved
};
},
});
5 changes: 5 additions & 0 deletions packages/core-state/src/wallets/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ export class Wallet implements State.IWallet {
audit.push({ "New username": username });
}

if (transaction.type === Enums.TransactionTypes.DelegateResignation) {
audit.push({ "Current username": this.username });
audit.push({ "New username": undefined });
}

if (transaction.type === Enums.TransactionTypes.Vote) {
audit.push({ "Current vote": this.vote });
audit.push({ "New vote": transaction.asset.votes[0] });
Expand Down
2 changes: 1 addition & 1 deletion packages/core-transaction-pool/src/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const defaults = {
ipfs: 250,
timelockTransfer: 500,
multiPayment: 500,
delegateResignation: 400000,
delegateResignation: 100,
},
},
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { EventEmitter, State } from "@arkecosystem/core-interfaces";
import { EventEmitter, State, TransactionPool } from "@arkecosystem/core-interfaces";
import { Interfaces, Transactions } from "@arkecosystem/crypto";
import { WalletUsernameEmptyError } from "../errors";
import { TransactionHandler } from "./transaction";

export class DelegateResignationTransactionHandler extends TransactionHandler {
Expand All @@ -12,13 +13,51 @@ export class DelegateResignationTransactionHandler extends TransactionHandler {
wallet: State.IWallet,
databaseWalletManager: State.IWalletManager,
): boolean {
if (!wallet.username || !transaction.data.asset.delegate.username) {
faustbrian marked this conversation as resolved.
Show resolved Hide resolved
throw new WalletUsernameEmptyError();
}

return super.canBeApplied(transaction, wallet, databaseWalletManager);
}

public emitEvents(transaction: Interfaces.ITransaction, emitter: EventEmitter.EventEmitter): void {
emitter.emit("delegate.resigned", transaction.data);
}

public canEnterTransactionPool(
data: Interfaces.ITransactionData,
pool: TransactionPool.IConnection,
processor: TransactionPool.IProcessor,
): boolean {
if (this.typeFromSenderAlreadyInPool(data, pool, processor)) {
processor.pushError(data, "ERR_PENDING",
`Delegate resignation for "${data.asset.delegate.username}" already in the pool`);
return false;
}

return true;
}

protected applyToSender(transaction: Interfaces.ITransaction, walletManager: State.IWalletManager): void {
super.applyToSender(transaction, walletManager);

const sender: State.IWallet = walletManager.findByPublicKey(transaction.data.senderPublicKey);

walletManager.forgetByUsername(sender.username);

sender.username = undefined;
}

protected revertForSender(transaction: Interfaces.ITransaction, walletManager: State.IWalletManager): void {
super.revertForSender(transaction, walletManager);

const sender: State.IWallet = walletManager.findByPublicKey(transaction.data.senderPublicKey);

sender.username = transaction.data.asset.delegate.username;

walletManager.reindex(sender);
}

protected applyToRecipient(transaction: Interfaces.ITransaction, walletManager: State.IWalletManager): void {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/bin/config/devnet/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = {
ipfs: 250,
timelockTransfer: 500,
multiPayment: 500,
delegateResignation: 400000,
delegateResignation: 100,
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion packages/core/bin/config/mainnet/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = {
ipfs: 250,
timelockTransfer: 500,
multiPayment: 500,
delegateResignation: 400000,
delegateResignation: 100,
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion packages/core/bin/config/testnet/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = {
ipfs: 250,
timelockTransfer: 500,
multiPayment: 500,
delegateResignation: 400000,
delegateResignation: 100,
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@ export class DelegateResignationBuilder extends TransactionBuilder<DelegateResig
this.data.type = TransactionTypes.DelegateResignation;
this.data.fee = feeManager.get(TransactionTypes.DelegateResignation);
this.data.amount = BigNumber.ZERO;
this.data.asset = {};
this.data.recipientId = undefined;
this.data.senderPublicKey = undefined;
this.data.asset = { delegate: {} } as ITransactionAsset;
}

public usernameAsset(username: string): DelegateResignationBuilder {
faustbrian marked this conversation as resolved.
Show resolved Hide resolved
this.data.asset.delegate.username = username;
return this;
}

public getStruct(): ITransactionData {
const struct: ITransactionData = super.getStruct();
struct.amount = this.data.amount;
struct.recipientId = this.data.recipientId;
faustbrian marked this conversation as resolved.
Show resolved Hide resolved
struct.asset = this.data.asset;
return struct;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/crypto/src/transactions/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export class Serializer {
break;
}

case TransactionTypes.DelegateRegistration: {
case TransactionTypes.DelegateRegistration:
case TransactionTypes.DelegateResignation: {
faustbrian marked this conversation as resolved.
Show resolved Hide resolved
assetBytes = Buffer.from(transaction.asset.delegate.username, "utf8");
assetSize = assetBytes.length;
break;
Expand Down
16 changes: 14 additions & 2 deletions packages/crypto/src/transactions/types/delegate-resignation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,22 @@ export class DelegateResignationTransaction extends Transaction {
}

public serialize(options?: ISerializeOptions): ByteBuffer {
return new ByteBuffer(0);
faustbrian marked this conversation as resolved.
Show resolved Hide resolved
const delegateBytes: Buffer = Buffer.from(this.data.asset.delegate.username, "utf8");
const buffer: ByteBuffer = new ByteBuffer(delegateBytes.length, true);

buffer.writeByte(delegateBytes.length);
buffer.append(delegateBytes, "hex");

return buffer;
}

public deserialize(buf: ByteBuffer): void {
return;
faustbrian marked this conversation as resolved.
Show resolved Hide resolved
const usernamelength: number = buf.readUint8();

this.data.asset = {
delegate: {
username: buf.readString(usernamelength),
},
};
}
}
14 changes: 14 additions & 0 deletions packages/crypto/src/transactions/types/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,23 @@ export const multiPayment = extend(transactionBaseSchema, {

export const delegateResignation = extend(transactionBaseSchema, {
$id: "delegateResignation",
required: ["asset"],
properties: {
type: { transactionType: TransactionTypes.DelegateResignation },
amount: { bignumber: { minimum: 0, maximum: 0 } },
asset: {
faustbrian marked this conversation as resolved.
Show resolved Hide resolved
type: "object",
required: ["delegate"],
properties: {
delegate: {
type: "object",
required: ["username"],
properties: {
username: { $ref: "delegateUsername" },
},
},
},
},
},
});

Expand Down