src/main/generic/consensus/base/account/Account.js
/**
* @abstract
*/
class Account {
/**
* @param {Account.Type} type
* @param {number} balance
*/
constructor(type, balance) {
if (!NumberUtils.isUint8(type)) throw new Error('Malformed type');
if (!NumberUtils.isUint64(balance)) throw new Error('Malformed balance');
/** @type {Account.Type} */
this._type = type;
/** @type {number} */
this._balance = balance;
}
/**
* Create Account object from binary form.
* @param {SerialBuffer} buf Buffer to read from.
* @return {Account} Newly created Account object.
*/
static unserialize(buf) {
const type = /** @type {Account.Type} */ buf.readUint8();
buf.readPos--;
if (!Account.TYPE_MAP.has(type)) {
throw new Error('Unknown account type');
}
return Account.TYPE_MAP.get(type).unserialize(buf);
}
/**
* Serialize this Account object into binary form.
* @param {?SerialBuffer} [buf] Buffer to write to.
* @return {SerialBuffer} Buffer from `buf` or newly generated one.
*/
serialize(buf) {
buf = buf || new SerialBuffer(this.serializedSize);
buf.writeUint8(this._type);
buf.writeUint64(this._balance);
return buf;
}
/**
* @return {number}
*/
get serializedSize() {
return /*type*/ 1
+ /*balance*/ 8;
}
/**
* Check if two Accounts are the same.
* @param {Account} o Object to compare with.
* @return {boolean} Set if both objects describe the same data.
*/
equals(o) {
return BufferUtils.equals(this.serialize(), o.serialize());
}
toString() {
return `Account{type=${this._type}, balance=${this._balance.toString()}`;
}
/**
* @type {number} Account balance
*/
get balance() {
return this._balance;
}
/** @type {Account.Type} */
get type() {
return this._type;
}
/**
* @param {number} balance
* @return {Account|*}
*/
withBalance(balance) { throw new Error('Not yet implemented.'); }
/**
* @param {Transaction} transaction
* @param {number} blockHeight
* @param {TransactionCache} transactionsCache
* @param {boolean} [revert]
* @return {Account}
*/
withOutgoingTransaction(transaction, blockHeight, transactionsCache, revert = false) {
if (!revert) {
const newBalance = this._balance - transaction.value - transaction.fee;
if (newBalance < 0) {
throw new Error('Balance Error!');
}
if (blockHeight < transaction.validityStartHeight
|| blockHeight >= transaction.validityStartHeight + Policy.TRANSACTION_VALIDITY_WINDOW) {
throw new Error('Validity Error!');
}
if (transactionsCache.containsTransaction(transaction)) {
throw new Error('Double Transaction Error!');
}
return this.withBalance(newBalance);
} else {
if (blockHeight < transaction.validityStartHeight
|| blockHeight >= transaction.validityStartHeight + Policy.TRANSACTION_VALIDITY_WINDOW) {
throw new Error('Validity Error!');
}
return this.withBalance(this._balance + transaction.value + transaction.fee);
}
}
/**
* @param {Transaction} transaction
* @param {number} blockHeight
* @param {boolean} [revert]
* @return {Account}
*/
withIncomingTransaction(transaction, blockHeight, revert = false) {
if (!revert) {
return this.withBalance(this._balance + transaction.value);
} else {
const newBalance = this._balance - transaction.value;
if (newBalance < 0) {
throw new Error('Balance Error!');
}
return this.withBalance(newBalance);
}
}
/**
* @param {Transaction} transaction
* @param {number} blockHeight
* @param {boolean} [revert]
* @return {Account}
*/
withContractCommand(transaction, blockHeight, revert = false) {
throw new Error('Not yet implemented');
}
/**
* @return {boolean}
*/
isInitial() {
return this === Account.INITIAL;
}
/**
* @return {boolean}
*/
isToBePruned() {
return this._balance === 0 && !this.isInitial();
}
}
/**
* Enum for Account types.
* Non-zero values are contracts.
* @enum
*/
Account.Type = {
/**
* Basic account type.
* @see {BasicAccount}
*/
BASIC: 0,
/**
* Account with vesting functionality.
* @see {VestingContract}
*/
VESTING: 1,
/**
* Hashed Time-Locked Contract
* @see {HashedTimeLockedContract}
*/
HTLC: 2
};
/**
* @type {Map.<Account.Type, {copy: function(o: *):Account, unserialize: function(buf: SerialBuffer):Account, create: function(balance: number, blockHeight: number, transaction: Transaction):Account, verifyOutgoingTransaction: function(transaction: Transaction):Promise.<boolean>, verifyIncomingTransaction: function(transaction: Transaction):Promise.<boolean>}>}
*/
Account.TYPE_MAP = new Map();
Class.register(Account);