@@ -205,6 +205,23 @@ func (t *Tx) UnmarshalBinary(b []byte) error {
205
205
return t .Tx .Deserialize (bytes .NewReader (b ))
206
206
}
207
207
208
+ var bogusSigScript = make ([]byte , 108 ) // worst case size to redeem a P2PKH
209
+
210
+ func (t * Tx ) estimateSerializeSize (tx * wire.MsgTx , mcount int ) int {
211
+ bogusMixedOut := & wire.TxOut {
212
+ Value : t .mixValue ,
213
+ Version : t .sc .version (),
214
+ PkScript : make ([]byte , t .sc .scriptSize ()),
215
+ }
216
+ for _ , in := range tx .TxIn {
217
+ in .SignatureScript = bogusSigScript
218
+ }
219
+ for i := 0 ; i < mcount ; i ++ {
220
+ tx .AddTxOut (bogusMixedOut )
221
+ }
222
+ return tx .SerializeSize ()
223
+ }
224
+
208
225
func feeForSerializeSize (relayFeePerKb int64 , txSerializeSize int ) int64 {
209
226
fee := relayFeePerKb * int64 (txSerializeSize ) / 1000
210
227
@@ -220,6 +237,17 @@ func feeForSerializeSize(relayFeePerKb int64, txSerializeSize int) int64 {
220
237
return fee
221
238
}
222
239
240
+ // highFeeRate is the maximum multiplier of the standard fee rate before unmixed
241
+ // data is refused for paying too high of a fee. It should not be too low such
242
+ // that mixing outputs at the smallest common mixed value errors for too high
243
+ // fees, as these mixes are performed without any change outputs.
244
+ const highFeeRate = 150
245
+
246
+ func paysHighFees (fee , relayFeePerKb int64 , txSerializeSize int ) bool {
247
+ maxFee := feeForSerializeSize (highFeeRate * relayFeePerKb , txSerializeSize )
248
+ return fee > maxFee
249
+ }
250
+
223
251
func (t * Tx ) ValidateUnmixed (unmixed []byte , mcount int ) error {
224
252
var fee int64
225
253
other := new (wire.MsgTx )
@@ -253,18 +281,15 @@ func (t *Tx) ValidateUnmixed(unmixed []byte, mcount int) error {
253
281
return err
254
282
}
255
283
fee -= int64 (mcount ) * t .mixValue
256
- bogusMixedOut := & wire.TxOut {
257
- Value : t .mixValue ,
258
- Version : t .sc .version (),
259
- PkScript : make ([]byte , t .sc .scriptSize ()),
260
- }
261
- for i := 0 ; i < mcount ; i ++ {
262
- other .AddTxOut (bogusMixedOut )
263
- }
264
- requiredFee := feeForSerializeSize (t .feeRate , other .SerializeSize ())
284
+ size := t .estimateSerializeSize (other , mcount )
285
+ requiredFee := feeForSerializeSize (t .feeRate , size )
265
286
if fee < requiredFee {
266
287
return errors .New ("coinjoin: unmixed transaction does not pay enough network fees" )
267
288
}
289
+ if paysHighFees (fee , t .feeRate , size ) {
290
+ return errors .New ("coinjoin: unmixed transaction pays insanely high fees" )
291
+ }
292
+
268
293
return nil
269
294
}
270
295
0 commit comments