OSDN Git Service

add cancel vote (#172)
[bytom/vapor.git] / protocol / validation / tx.go
index 64fbde9..ce5feac 100644 (file)
@@ -265,30 +265,13 @@ func checkValid(vs *validationState, e bc.Entry) (err error) {
                if e.SpentOutputId == nil {
                        return errors.Wrap(ErrMissingField, "spend without spent output ID")
                }
-               var (
-                       controlProgram *bc.Program
-                       value          *bc.AssetAmount
-               )
-               entryOutput, err := vs.tx.Entry(*e.SpentOutputId)
+
+               spentOutput, err := vs.tx.IntraChainOutput(*e.SpentOutputId)
                if err != nil {
                        return errors.Wrap(err, "getting spend prevout")
                }
 
-               switch output := entryOutput.(type) {
-               case *bc.IntraChainOutput:
-                       controlProgram = output.ControlProgram
-                       value = output.Source.Value
-               case *bc.VoteOutput:
-                       if len(output.Vote) != 64 {
-                               return ErrVotePubKey
-                       }
-                       controlProgram = output.ControlProgram
-                       value = output.Source.Value
-               default:
-                       return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", e.SpentOutputId.Bytes(), entryOutput)
-               }
-
-               gasLeft, err := vm.Verify(NewTxVMContext(vs, e, controlProgram, e.WitnessArguments), vs.gasStatus.GasLeft)
+               gasLeft, err := vm.Verify(NewTxVMContext(vs, e, spentOutput.ControlProgram, e.WitnessArguments), vs.gasStatus.GasLeft)
                if err != nil {
                        return errors.Wrap(err, "checking control program")
                }
@@ -296,7 +279,7 @@ func checkValid(vs *validationState, e bc.Entry) (err error) {
                        return err
                }
 
-               eq, err := value.Equal(e.WitnessDestination.Value)
+               eq, err := spentOutput.Source.Value.Equal(e.WitnessDestination.Value)
                if err != nil {
                        return err
                }
@@ -304,8 +287,8 @@ func checkValid(vs *validationState, e bc.Entry) (err error) {
                        return errors.WithDetailf(
                                ErrMismatchedValue,
                                "previous output is for %d unit(s) of %x, spend wants %d unit(s) of %x",
-                               value.Amount,
-                               value.AssetId.Bytes(),
+                               spentOutput.Source.Value.Amount,
+                               spentOutput.Source.Value.AssetId.Bytes(),
                                e.WitnessDestination.Value.Amount,
                                e.WitnessDestination.Value.AssetId.Bytes(),
                        )
@@ -316,6 +299,47 @@ func checkValid(vs *validationState, e bc.Entry) (err error) {
                        return errors.Wrap(err, "checking spend destination")
                }
 
+       case *bc.VetoInput:
+               if e.SpentOutputId == nil {
+                       return errors.Wrap(ErrMissingField, "vetoInput without vetoInput output ID")
+               }
+
+               voteOutput, err := vs.tx.VoteOutput(*e.SpentOutputId)
+               if err != nil {
+                       return errors.Wrap(err, "getting vetoInput prevout")
+               }
+               if len(voteOutput.Vote) != 64 {
+                       return ErrVotePubKey
+               }
+
+               gasLeft, err := vm.Verify(NewTxVMContext(vs, e, voteOutput.ControlProgram, e.WitnessArguments), vs.gasStatus.GasLeft)
+               if err != nil {
+                       return errors.Wrap(err, "checking control program")
+               }
+               if err = vs.gasStatus.updateUsage(gasLeft); err != nil {
+                       return err
+               }
+
+               eq, err := voteOutput.Source.Value.Equal(e.WitnessDestination.Value)
+               if err != nil {
+                       return err
+               }
+               if !eq {
+                       return errors.WithDetailf(
+                               ErrMismatchedValue,
+                               "previous output is for %d unit(s) of %x, vetoInput wants %d unit(s) of %x",
+                               voteOutput.Source.Value.Amount,
+                               voteOutput.Source.Value.AssetId.Bytes(),
+                               e.WitnessDestination.Value.Amount,
+                               e.WitnessDestination.Value.AssetId.Bytes(),
+                       )
+               }
+               vs2 := *vs
+               vs2.destPos = 0
+               if err = checkValidDest(&vs2, e.WitnessDestination); err != nil {
+                       return errors.Wrap(err, "checking vetoInput destination")
+               }
+
        case *bc.Coinbase:
                if vs.block == nil || len(vs.block.Transactions) == 0 || vs.block.Transactions[0] != vs.tx {
                        return ErrWrongCoinbaseTransaction
@@ -367,6 +391,12 @@ func checkValidSrc(vstate *validationState, vs *bc.ValueSource) error {
 
        var dest *bc.ValueDestination
        switch ref := e.(type) {
+       case *bc.VetoInput:
+               if vs.Position != 0 {
+                       return errors.Wrapf(ErrPosition, "invalid position %d for veto-input source", vs.Position)
+               }
+               dest = ref.WitnessDestination
+
        case *bc.Coinbase:
                if vs.Position != 0 {
                        return errors.Wrapf(ErrPosition, "invalid position %d for coinbase source", vs.Position)