Skip to content

Commit

Permalink
Protocol 13 support (#317)
Browse files Browse the repository at this point in the history
* Update XDR definitions.

* Fix hash generation with v1 or v0 transactions.

* Pass networkPassphrase.

* Fix transaction envelope for TransactionV1Envelope.

* Fix more transaction related tests.

* Update type for allowTrust.

* Fix test for authorize.

* Build a TransactionV0.

* Add comment on TS types.
  • Loading branch information
abuiles committed Apr 20, 2020
1 parent b81db11 commit 91b0465
Show file tree
Hide file tree
Showing 10 changed files with 3,488 additions and 2,946 deletions.
6,044 changes: 3,187 additions & 2,857 deletions src/generated/stellar-xdr_generated.js

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions src/operations/allow_trust.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { StrKey } from '../strkey';
* @param {object} opts Options object
* @param {string} opts.trustor - The trusting account (the one being authorized)
* @param {string} opts.assetCode - The asset code being authorized.
* @param {boolean} opts.authorize - True to authorize the line, false to deauthorize.
* @param {boolean|number} opts.authorize - True to authorize the line, false to deauthorize.
* @param {string} [opts.source] - The source account (defaults to transaction source).
* @returns {xdr.AllowTrustOp} Allow Trust operation
*/
Expand All @@ -30,7 +30,13 @@ export function allowTrust(opts) {
} else {
throw new Error('Asset code must be 12 characters at max.');
}
attributes.authorize = opts.authorize;

if (typeof opts.authorize === 'boolean') {
attributes.authorize = +opts.authorize;
} else {
attributes.authorize = opts.authorize;
}

const allowTrustOp = new xdr.AllowTrustOp(attributes);

const opAttributes = {};
Expand Down
75 changes: 61 additions & 14 deletions src/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,27 @@ export class Transaction {
}
this._networkPassphrase = networkPassphrase;

const txe = envelope.value();
let sourceAccount;
this._envelopeType = envelope.switch();
switch (this._envelopeType) {
case xdr.EnvelopeType.envelopeTypeTxV0():
sourceAccount = txe.tx().sourceAccountEd25519();
break;
case xdr.EnvelopeType.envelopeTypeTx():
sourceAccount = txe
.tx()
.sourceAccount()
.ed25519();
break;
default:
// TODO: Add support for FeeBumpTransaction
throw new Error('Invalid transaction.');
}

// since this transaction is immutable, save the tx
this.tx = envelope.tx();
this.source = StrKey.encodeEd25519PublicKey(
envelope
.tx()
.sourceAccount()
.ed25519()
);
this.tx = txe.tx();
this.source = StrKey.encodeEd25519PublicKey(sourceAccount);
this.fee = this.tx.fee();
this._memo = this.tx.memo();
this.sequence = this.tx.seqNum().toString();
Expand All @@ -62,7 +75,7 @@ export class Transaction {
const operations = this.tx.operations() || [];
this.operations = map(operations, (op) => Operation.fromXDRObject(op));

const signatures = envelope.signatures() || [];
const signatures = txe.signatures() || [];
this.signatures = map(signatures, (s) => s);
}

Expand Down Expand Up @@ -229,11 +242,30 @@ export class Transaction {
* @returns {Buffer}
*/
signatureBase() {
return Buffer.concat([
hash(this.networkPassphrase),
xdr.EnvelopeType.envelopeTypeTx().toXDR(),
this.tx.toXDR()
]);
let tx = this.tx;

// Backwards Compatibility: Use ENVELOPE_TYPE_TX to sign ENVELOPE_TYPE_TX_V0
// we need a Transaction to generate the signature base
if (this._envelopeType === xdr.EnvelopeType.envelopeTypeTxV0()) {
tx = xdr.Transaction.fromXDR(
Buffer.concat([
// TransactionV0 is a transaction with the AccountID discriminant
// stripped off, we need to put it back to build a valid transaction
// which we can use to build a TransactionSignaturePayloadTaggedTransaction
xdr.PublicKeyType.publicKeyTypeEd25519().toXDR(),
tx.toXDR()
])
);
}

const txSignature = new xdr.TransactionSignaturePayload({
networkId: xdr.Hash.fromXDR(hash(this.networkPassphrase)),
taggedTransaction: new xdr.TransactionSignaturePayloadTaggedTransaction.envelopeTypeTx(
tx
)
});

return txSignature.toXDR();
}

/**
Expand All @@ -243,7 +275,22 @@ export class Transaction {
toEnvelope() {
const tx = this.tx;
const signatures = this.signatures;
const envelope = new xdr.TransactionEnvelope({ tx, signatures });

let envelope;
switch (this._envelopeType) {
case xdr.EnvelopeType.envelopeTypeTxV0():
envelope = new xdr.TransactionEnvelope.envelopeTypeTxV0(
new xdr.TransactionV0Envelope({ tx, signatures })
);
break;
case xdr.EnvelopeType.envelopeTypeTx():
envelope = new xdr.TransactionEnvelope.envelopeTypeTx(
new xdr.TransactionV1Envelope({ tx, signatures })
);
break;
default:
throw new Error('Invalid transaction');
}

return envelope;
}
Expand Down
31 changes: 21 additions & 10 deletions src/transaction_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,16 +184,20 @@ export class TransactionBuilder {
build() {
const sequenceNumber = new BigNumber(this.source.sequenceNumber()).add(1);
const attrs = {
sourceAccount: Keypair.fromPublicKey(
this.source.accountId()
).xdrAccountId(),
sourceAccountEd25519: Keypair.fromPublicKey(this.source.accountId())
.xdrAccountId()
.value(),
fee: this.baseFee * this.operations.length,
seqNum: xdr.SequenceNumber.fromString(sequenceNumber.toString()),
memo: this.memo ? this.memo.toXDRObject() : null,
ext: new xdr.TransactionExt(0)
ext: new xdr.TransactionV0Ext(0)
};

if (this.timebounds === null || typeof this.timebounds.minTime === 'undefined' || typeof this.timebounds.maxTime === 'undefined') {
if (
this.timebounds === null ||
typeof this.timebounds.minTime === 'undefined' ||
typeof this.timebounds.maxTime === 'undefined'
) {
throw new Error(
'TimeBounds has to be set or you must call setTimeout(TimeoutInfinite).'
);
Expand All @@ -206,15 +210,22 @@ export class TransactionBuilder {
this.timebounds.maxTime = this.timebounds.maxTime.getTime() / 1000;
}

this.timebounds.minTime = UnsignedHyper.fromString(this.timebounds.minTime.toString());
this.timebounds.maxTime = UnsignedHyper.fromString(this.timebounds.maxTime.toString())

this.timebounds.minTime = UnsignedHyper.fromString(
this.timebounds.minTime.toString()
);
this.timebounds.maxTime = UnsignedHyper.fromString(
this.timebounds.maxTime.toString()
);

attrs.timeBounds = new xdr.TimeBounds(this.timebounds);

const xtx = new xdr.Transaction(attrs);
const xtx = new xdr.TransactionV0(attrs);
xtx.operations(this.operations);

const xenv = new xdr.TransactionEnvelope({ tx: xtx });
const xenv = new xdr.TransactionEnvelope.envelopeTypeTxV0(
new xdr.TransactionV0Envelope({ tx: xtx })
);

const tx = new Transaction(xenv, this.networkPassphrase);

this.source.incrementSequenceNumber();
Expand Down
2 changes: 1 addition & 1 deletion test/unit/operation_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ describe('Operation', function() {
expect(obj.type).to.be.equal('allowTrust');
expect(obj.trustor).to.be.equal(trustor);
expect(obj.assetCode).to.be.equal(assetCode);
expect(obj.authorize).to.be.equal(authorize);
expect(obj.authorize).to.be.equal(1);
});

it('fails to create allowTrust operation with an invalid trustor address', function() {
Expand Down
20 changes: 10 additions & 10 deletions test/unit/transaction_envelope_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ describe('TransactionEnvelope', function() {
let xdr =
'AAAAAPQQv+uPYrlCDnjgPyPRgIjB6T8Zb8ANmL8YGAXC2IAgAAAAZAAIteYAAAAHAAAAAAAAAAAAAAABAAAAAAAAAAMAAAAAAAAAAUVVUgAAAAAAUtYuFczBLlsXyEp3q8BbTBpEGINWahqkFbnTPd93YUUAAAAXSHboAAAAABEAACcQAAAAAAAAAKIAAAAAAAAAAcLYgCAAAABAo2tU6n0Bb7bbbpaXacVeaTVbxNMBtnrrXVk2QAOje2Flllk/ORlmQdFU/9c8z43eWh1RNMpI3PscY+yDCnJPBQ==';

var txe = StellarBase.xdr.TransactionEnvelope.fromXDR(xdr, 'base64');
expect(
txe
.tx()
.sourceAccount()
.value().length
).to.be.equal(32);
let txe = StellarBase.xdr.TransactionEnvelope.fromXDR(
xdr,
'base64'
).value();
let sourceAccount = txe.tx().sourceAccountEd25519();

expect(sourceAccount.length).to.be.equal(32);
done();
});

it('calculates correct hash with non-utf8 strings', function() {
it('calculates correct hash with non-utf8 strings', function(done) {
// a84d534b3742ad89413bdbf259e02fa4c5d039123769e9bcc63616f723a2bcd5
let xdr =
'AAAAAAtjwtJadppTmm0NtAU99BFxXXfzPO1N/SqR43Z8aXqXAAAAZAAIj6YAAAACAAAAAAAAAAEAAAAB0QAAAAAAAAEAAAAAAAAAAQAAAADLa6390PDAqg3qDLpshQxS+uVw3ytSgKRirQcInPWt1QAAAAAAAAAAA1Z+AAAAAAAAAAABfGl6lwAAAEBC655+8Izq54MIZrXTVF/E1ycHgQWpVcBD+LFkuOjjJd995u/7wM8sFqQqambL0/ME2FTOtxMO65B9i3eAIu4P';
var tx = new StellarBase.Transaction(xdr);
StellarBase.Network.usePublicNetwork();
var tx = new StellarBase.Transaction(xdr, StellarBase.Networks.PUBLIC);
expect(tx.hash().toString('hex')).to.be.equal(
'a84d534b3742ad89413bdbf259e02fa4c5d039123769e9bcc63616f723a2bcd5'
);
done();
});
});
Loading

0 comments on commit 91b0465

Please sign in to comment.