package validation
import (
+ "bytes"
"fmt"
"math"
+ "github.com/vapor/config"
"github.com/vapor/consensus"
"github.com/vapor/consensus/segwit"
"github.com/vapor/errors"
ErrUnbalanced = errors.New("unbalanced asset amount between input and output")
ErrOverGasCredit = errors.New("all gas credit has been spend")
ErrGasCalculate = errors.New("gas usage calculate got a math error")
+ ErrVotePubKey = errors.New("invalid public key of vote")
+ ErrVoteOutputAmount = errors.New("invalid vote amount")
)
// GasState record the gas usage status
}
case *bc.VoteOutput:
+ if len(e.Vote) != 64 {
+ return ErrVotePubKey
+ }
vs2 := *vs
vs2.sourcePos = 0
if err = checkValidSrc(&vs2, e.Source); err != nil {
- return errors.Wrap(err, "checking output source")
+ return errors.Wrap(err, "checking vote output source")
+ }
+ if e.Source.Value.Amount < consensus.MinVoteOutputAmount {
+ return ErrVoteOutputAmount
}
case *bc.Retirement:
if err = checkValidDest(&vs2, e.WitnessDestination); err != nil {
return errors.Wrap(err, "checking cross-chain input destination")
}
+ vs.gasStatus.StorageGas = 0
case *bc.Spend:
if e.SpentOutputId == nil {
return errors.Wrap(ErrMissingField, "spend without spent output ID")
}
- spentOutput, err := vs.tx.IntraChainOutput(*e.SpentOutputId)
+ var (
+ controlProgram *bc.Program
+ value *bc.AssetAmount
+ )
+ entryOutput, err := vs.tx.Entry(*e.SpentOutputId)
if err != nil {
return errors.Wrap(err, "getting spend prevout")
}
- gasLeft, err := vm.Verify(NewTxVMContext(vs, e, spentOutput.ControlProgram, e.WitnessArguments), vs.gasStatus.GasLeft)
+
+ 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)
if err != nil {
return errors.Wrap(err, "checking control program")
}
if err = vs.gasStatus.updateUsage(gasLeft); err != nil {
return err
}
- eq, err := spentOutput.Source.Value.Equal(e.WitnessDestination.Value)
+
+ eq, err := value.Equal(e.WitnessDestination.Value)
if err != nil {
return err
}
return errors.WithDetailf(
ErrMismatchedValue,
"previous output is for %d unit(s) of %x, spend wants %d unit(s) of %x",
- spentOutput.Source.Value.Amount,
- spentOutput.Source.Value.AssetId.Bytes(),
+ value.Amount,
+ value.AssetId.Bytes(),
e.WitnessDestination.Value.Amount,
e.WitnessDestination.Value.AssetId.Bytes(),
)
return nil
}
+func checkFedaration(tx *bc.Tx) error {
+ for _, id := range tx.InputIDs {
+ switch inp := tx.Entries[id].(type) {
+ case *bc.CrossChainInput:
+ fedProg := config.FederationProgrom(config.CommonConfig)
+ if !bytes.Equal(inp.ControlProgram.Code, fedProg) {
+ return errors.New("The federal controlProgram is incorrect")
+ }
+ default:
+ continue
+ }
+ }
+ return nil
+}
+
func checkStandardTx(tx *bc.Tx, blockHeight uint64) error {
for _, id := range tx.InputIDs {
if blockHeight >= ruleAA && id.IsZero() {
}
}
+ if err := checkFedaration(tx); err != nil {
+ return err
+ }
+
for _, id := range tx.GasInputIDs {
spend, err := tx.Spend(id)
if err != nil {