@@ -374,51 +374,6 @@ impl Default for TransactionDecoder {
374374 fn default ( ) -> Self { Self :: new ( ) }
375375}
376376
377- #[ cfg( feature = "alloc" ) ]
378- impl TransactionDecoderState {
379- #[ track_caller]
380- fn version_transition ( & mut self ) -> VersionDecoder {
381- match mem:: replace ( self , TransactionDecoderState :: Transitioning ) {
382- TransactionDecoderState :: Version ( decoder) => decoder,
383- _ => panic ! ( "transition called on invalid state" ) ,
384- }
385- }
386-
387- #[ track_caller]
388- fn inputs_transition ( & mut self ) -> VecDecoder < TxIn > {
389- match mem:: replace ( self , TransactionDecoderState :: Transitioning ) {
390- TransactionDecoderState :: Inputs ( _, _, decoder) => decoder,
391- _ => panic ! ( "transition called on invalid state" ) ,
392- }
393- }
394-
395- #[ track_caller]
396- fn outputs_transition ( & mut self ) -> ( Vec < TxIn > , VecDecoder < TxOut > ) {
397- match mem:: replace ( self , TransactionDecoderState :: Transitioning ) {
398- TransactionDecoderState :: Outputs ( _, inputs, _, decoder) => ( inputs, decoder) ,
399- _ => panic ! ( "transition called on invalid state" ) ,
400- }
401- }
402-
403- #[ track_caller]
404- fn witness_transition ( & mut self ) -> ( Vec < TxIn > , Vec < TxOut > , WitnessDecoder ) {
405- match mem:: replace ( self , TransactionDecoderState :: Transitioning ) {
406- TransactionDecoderState :: Witnesses ( _, inputs, outputs, _, decoder) =>
407- ( inputs, outputs, decoder) ,
408- _ => panic ! ( "transition called on invalid state" ) ,
409- }
410- }
411-
412- #[ track_caller]
413- fn lock_time_transition ( & mut self ) -> ( Vec < TxIn > , Vec < TxOut > , LockTimeDecoder ) {
414- match mem:: replace ( self , TransactionDecoderState :: Transitioning ) {
415- TransactionDecoderState :: LockTime ( _, inputs, outputs, decoder) =>
416- ( inputs, outputs, decoder) ,
417- _ => panic ! ( "transition called on invalid state" ) ,
418- }
419- }
420- }
421-
422377#[ cfg( feature = "alloc" ) ]
423378#[ allow( clippy:: too_many_lines) ] // TODO: Can we clean this up?
424379impl Decoder for TransactionDecoder {
@@ -433,25 +388,50 @@ impl Decoder for TransactionDecoder {
433388 } ;
434389
435390 loop {
391+ // Attempt to push to the currently-active decoder and return early on success.
436392 match & mut self . state {
437393 State :: Version ( decoder) => {
438394 if decoder. push_bytes ( bytes) ? {
439395 // Still more bytes required.
440396 return Ok ( true ) ;
441397 }
442- let decoder = self . state . version_transition ( ) ;
443- let version = decoder. end ( ) ?;
444- self . state = State :: Inputs ( version, Attempt :: First , VecDecoder :: < TxIn > :: new ( ) ) ;
445- }
446- State :: Inputs ( version, attempt, decoder) => {
398+ } ,
399+ State :: Inputs ( _, _, decoder) => {
400+ if decoder. push_bytes ( bytes) ? {
401+ return Ok ( true ) ;
402+ }
403+ } ,
404+ State :: SegwitFlag ( _) => {
405+ if bytes. is_empty ( ) {
406+ return Ok ( true ) ;
407+ }
408+ } ,
409+ State :: Outputs ( _, _, _, decoder) => {
410+ if decoder. push_bytes ( bytes) ? {
411+ return Ok ( true ) ;
412+ }
413+ } ,
414+ State :: Witnesses ( _, _, _, _, decoder) => {
415+ if decoder. push_bytes ( bytes) ? {
416+ return Ok ( true ) ;
417+ }
418+ } ,
419+ State :: LockTime ( _, _, _, decoder) => {
447420 if decoder. push_bytes ( bytes) ? {
448421 return Ok ( true ) ;
449422 }
450- // Copy the state because we need mutable access to self to transition.
451- let version = * version;
452- let attempt = * attempt;
423+ } ,
424+ State :: Done ( ..) => return Ok ( false ) ,
425+ State :: Errored => panic ! ( "call to push_bytes() after decoder errored" ) ,
426+ }
453427
454- let decoder = self . state . inputs_transition ( ) ;
428+ // If the above failed, end the current decoder and go to the next state.
429+ match mem:: replace ( & mut self . state , State :: Errored ) {
430+ State :: Version ( decoder) => {
431+ let version = decoder. end ( ) ?;
432+ self . state = State :: Inputs ( version, Attempt :: First , VecDecoder :: < TxIn > :: new ( ) ) ;
433+ }
434+ State :: Inputs ( version, attempt, decoder) => {
455435 let inputs = decoder. end ( ) ?;
456436
457437 if Attempt :: First == attempt {
@@ -475,11 +455,6 @@ impl Decoder for TransactionDecoder {
475455 }
476456 }
477457 State :: SegwitFlag ( version) => {
478- if bytes. is_empty ( ) {
479- return Ok ( true ) ;
480- }
481- let version = * version;
482-
483458 let segwit_flag = bytes[ 0 ] ;
484459 * bytes = & bytes[ 1 ..] ;
485460
@@ -488,17 +463,9 @@ impl Decoder for TransactionDecoder {
488463 }
489464 self . state = State :: Inputs ( version, Attempt :: Second , VecDecoder :: < TxIn > :: new ( ) ) ;
490465 }
491- State :: Outputs ( version, _, is_segwit, decoder) => {
492- if decoder. push_bytes ( bytes) ? {
493- return Ok ( true ) ;
494- }
495- // These types are Copy, so we can deref them but does not work for vectors.
496- let version = * version;
497- let is_segwit = * is_segwit;
498-
466+ State :: Outputs ( version, inputs, is_segwit, decoder) => {
499467 // We get the inputs vector here instead of in the pattern match because I
500468 // couldn't find another way to get it out of behind the mutable reference.
501- let ( inputs, decoder) = self . state . outputs_transition ( ) ;
502469 let outputs = decoder. end ( ) ?;
503470 if is_segwit == IsSegwit :: Yes {
504471 self . state = State :: Witnesses (
@@ -513,14 +480,9 @@ impl Decoder for TransactionDecoder {
513480 State :: LockTime ( version, inputs, outputs, LockTimeDecoder :: new ( ) ) ;
514481 }
515482 }
516- State :: Witnesses ( version, _, _, iteration, decoder) => {
517- if decoder. push_bytes ( bytes) ? {
518- return Ok ( true ) ;
519- }
520- let version = * version;
483+ State :: Witnesses ( version, mut inputs, outputs, iteration, decoder) => {
521484 let iteration = iteration. 0 ;
522485
523- let ( mut inputs, outputs, decoder) = self . state . witness_transition ( ) ;
524486 inputs[ iteration] . witness = decoder. end ( ) ?;
525487 if iteration < inputs. len ( ) - 1 {
526488 self . state = State :: Witnesses (
@@ -539,40 +501,33 @@ impl Decoder for TransactionDecoder {
539501 State :: LockTime ( version, inputs, outputs, LockTimeDecoder :: new ( ) ) ;
540502 }
541503 }
542- State :: LockTime ( version, _, _, decoder) => {
543- if decoder. push_bytes ( bytes) ? {
544- return Ok ( true ) ;
545- }
546- let version = * version;
547-
548- let ( inputs, outputs, decoder) = self . state . lock_time_transition ( ) ;
504+ State :: LockTime ( version, inputs, outputs, decoder) => {
549505 let lock_time = decoder. end ( ) ?;
550506 self . state = State :: Done ( Transaction { version, lock_time, inputs, outputs } ) ;
551507 return Ok ( false ) ;
552508 }
553509 State :: Done ( ..) => return Ok ( false ) ,
554- State :: Transitioning => {
555- panic ! ( "use of decoder in transitioning state" ) ;
556- }
510+ State :: Errored => unreachable ! ( "checked above" ) ,
557511 }
558512 }
559513 }
560514
561515 #[ inline]
562516 fn end ( self ) -> Result < Self :: Output , Self :: Error > {
563- use TransactionDecoderState as State ;
517+ use {
518+ TransactionDecoderError as E , TransactionDecoderErrorInner as Inner ,
519+ TransactionDecoderState as State ,
520+ } ;
564521
565522 match self . state {
566- State :: Version ( _) => panic ! ( "tried to end decoder in state: Version" ) ,
567- State :: Inputs ( ..) => panic ! ( "tried to end decoder in state: Inputs" ) ,
568- State :: SegwitFlag ( ..) => panic ! ( "tried to end decoder in state: SegwitFlag" ) ,
569- State :: Outputs ( ..) => panic ! ( "tried to end decoder in state: Outputs" ) ,
570- State :: Witnesses ( ..) => panic ! ( "tried to end decoder in state: Witnesses" ) ,
571- State :: LockTime ( ..) => panic ! ( "tried to end decoder in state: LockTime" ) ,
523+ State :: Version ( _) => Err ( E ( Inner :: EarlyEnd ( "version" ) ) ) ,
524+ State :: Inputs ( ..) => Err ( E ( Inner :: EarlyEnd ( "inputs" ) ) ) ,
525+ State :: SegwitFlag ( ..) => Err ( E ( Inner :: EarlyEnd ( "segwit flag" ) ) ) ,
526+ State :: Outputs ( ..) => Err ( E ( Inner :: EarlyEnd ( "outputs" ) ) ) ,
527+ State :: Witnesses ( ..) => Err ( E ( Inner :: EarlyEnd ( "witnesses" ) ) ) ,
528+ State :: LockTime ( ..) => Err ( E ( Inner :: EarlyEnd ( "locktime" ) ) ) ,
572529 State :: Done ( tx) => Ok ( tx) ,
573- State :: Transitioning => {
574- panic ! ( "use of decoder in transitioning state" ) ;
575- }
530+ State :: Errored => panic ! ( "call to end() after decoder errored" ) ,
576531 }
577532 }
578533
@@ -588,7 +543,9 @@ impl Decoder for TransactionDecoder {
588543 State :: Witnesses ( _, _, _, _, decoder) => decoder. read_limit ( ) ,
589544 State :: LockTime ( _, _, _, decoder) => decoder. read_limit ( ) ,
590545 State :: Done ( _) => 0 ,
591- State :: Transitioning => panic ! ( "use of decoder in transitioning state" ) ,
546+ // `read_limit` is not documented to panic or return an error, so we
547+ // return a dummy value if the decoder is in an error state.
548+ State :: Errored => 0 ,
592549 }
593550 }
594551}
@@ -616,8 +573,9 @@ enum TransactionDecoderState {
616573 LockTime ( Version , Vec < TxIn > , Vec < TxOut > , LockTimeDecoder ) ,
617574 /// Done decoding the [`Transaction`].
618575 Done ( Transaction ) ,
619- /// Temporary state during transitions, should never be observed.
620- Transitioning ,
576+ /// When `end()`ing a sub-decoder, encountered an error which prevented us
577+ /// from constructing the next sub-decoder.
578+ Errored ,
621579}
622580
623581/// Boolean used to track number of times we have attempted to decode the inputs vector.
@@ -667,6 +625,9 @@ enum TransactionDecoderErrorInner {
667625 NoWitnesses ,
668626 /// Error while decoding the `lock_time`.
669627 LockTime ( LockTimeDecoderError ) ,
628+ /// Attempt to call `end()` before the transaction was complete. Holds
629+ /// a description of the current state.
630+ EarlyEnd ( & ' static str ) ,
670631}
671632
672633#[ cfg( feature = "alloc" ) ]
@@ -717,6 +678,7 @@ impl fmt::Display for TransactionDecoderError {
717678 E :: Witness ( ref e) => write_err ! ( f, "transaction decoder error" ; e) ,
718679 E :: NoWitnesses => write ! ( f, "non-empty Segwit transaction with no witnesses" ) ,
719680 E :: LockTime ( ref e) => write_err ! ( f, "transaction decoder error" ; e) ,
681+ E :: EarlyEnd ( s) => write ! ( f, "early end of transaction (still decoding {})" , s) ,
720682 }
721683 }
722684}
@@ -735,6 +697,7 @@ impl std::error::Error for TransactionDecoderError {
735697 E :: Witness ( ref e) => Some ( e) ,
736698 E :: NoWitnesses => None ,
737699 E :: LockTime ( ref e) => Some ( e) ,
700+ E :: EarlyEnd ( _) => None ,
738701 }
739702 }
740703}
@@ -2153,6 +2116,16 @@ mod tests {
21532116 decoder. push_bytes ( & mut slice) . unwrap ( ) ;
21542117 let tx = decoder. end ( ) . unwrap ( ) ;
21552118
2119+ // Attempt various truncations
2120+ for i in [ 1 , 10 , 20 , 50 , 100 , tx_bytes. len ( ) / 2 , tx_bytes. len ( ) ] {
2121+ let mut decoder = Transaction :: decoder ( ) ;
2122+ let mut slice = & tx_bytes[ ..tx_bytes. len ( ) - i] ;
2123+ // push_bytes will not fail because the data is not invalid, just truncated
2124+ decoder. push_bytes ( & mut slice) . unwrap ( ) ;
2125+ // ...but end() will fail because we will be in some incomplete state
2126+ decoder. end ( ) . unwrap_err ( ) ;
2127+ }
2128+
21562129 // All these tests aren't really needed because if they fail, the hash check at the end
21572130 // will also fail. But these will show you where the failure is so I'll leave them in.
21582131 assert_eq ! ( tx. version, Version :: TWO ) ;
0 commit comments