diff --git a/src/ripple/app/tests/MultiSign.test.cpp b/src/ripple/app/tests/MultiSign.test.cpp index 2f9a78e5b..db01fc905 100644 --- a/src/ripple/app/tests/MultiSign.test.cpp +++ b/src/ripple/app/tests/MultiSign.test.cpp @@ -172,16 +172,35 @@ public: env.close(); expect (env.seq(alice) == aliceSeq); - // Multisign, but leave a nonempty sfSigners. Should fail. + // Multisign, but leave a nonempty sfSigningPubKey. Should fail. { aliceSeq = env.seq (alice); Json::Value multiSig = env.json (noop (alice), msig(bogie), fee(2 * baseFee)); - env (env.jt (multiSig), ter (temINVALID)); env.close(); expect (env.seq(alice) == aliceSeq); } + // Attach both Signers and a TxnSignature with an empty sfPubKey. + // Should fail. + { + aliceSeq = env.seq (alice); + Json::Value multiSig = env.json (noop (alice), + fee(2 * baseFee), seq(aliceSeq), sig(alice), msig(bogie)); + JTx jt = env.jt (multiSig); + jt.fill_fee = false; + jt.fill_seq = false; + jt.fill_sig = false; + jt.jv["SigningPubKey"] = ""; + + auto noSigPubKey = std::make_unique(*(jt.stx)); + noSigPubKey->setFieldVL (sfSigningPubKey, Blob()); + jt.stx.reset (noSigPubKey.release()); + + env (jt, ter (temINVALID)); + env.close(); + expect (env.seq(alice) == aliceSeq); + } // Don't meet the quorum. Should fail. env(signers(alice, 2, {{bogie, 1}, {demon, 1}})); diff --git a/src/ripple/protocol/impl/STTx.cpp b/src/ripple/protocol/impl/STTx.cpp index af66cc77d..42835f755 100644 --- a/src/ripple/protocol/impl/STTx.cpp +++ b/src/ripple/protocol/impl/STTx.cpp @@ -305,6 +305,11 @@ STTx::checkMultiSign () const if (!isFieldPresent (sfSigners)) return false; + // We don't allow both an sfSigners and an sfTxnSignature. Both fields + // being present would indicate that the transaction is signed both ways. + if (isFieldPresent (sfTxnSignature)) + return false; + STArray const& signers {getFieldArray (sfSigners)}; // There are well known bounds that the number of signers must be within.