return errors.Wrap(err, "checking output source")
}
- case *bc.Retirement:
+ case *bc.VoteOutput:
vs2 := *vs
vs2.sourcePos = 0
if err = checkValidSrc(&vs2, e.Source); err != nil {
- return errors.Wrap(err, "checking retirement source")
+ return errors.Wrap(err, "checking output source")
}
- case *bc.Issuance:
- computedAssetID := e.WitnessAssetDefinition.ComputeAssetID()
- if computedAssetID != *e.Value.AssetId {
- return errors.WithDetailf(ErrMismatchedAssetID, "asset ID is %x, issuance wants %x", computedAssetID.Bytes(), e.Value.AssetId.Bytes())
+ case *bc.Retirement:
+ vs2 := *vs
+ vs2.sourcePos = 0
+ if err = checkValidSrc(&vs2, e.Source); err != nil {
+ return errors.Wrap(err, "checking retirement source")
}
- gasLeft, err := vm.Verify(NewTxVMContext(vs, e, e.WitnessAssetDefinition.IssuanceProgram, e.WitnessArguments), vs.gasStatus.GasLeft)
+ case *bc.CrossChainInput:
+ _, err := vm.Verify(NewTxVMContext(vs, e, e.ControlProgram, e.WitnessArguments), consensus.DefaultGasCredit)
if err != nil {
- return errors.Wrap(err, "checking issuance program")
- }
- if err = vs.gasStatus.updateUsage(gasLeft); err != nil {
- return err
+ return errors.Wrap(err, "checking cross-chain input control program")
}
- destVS := *vs
- destVS.destPos = 0
- if err = checkValidDest(&destVS, e.WitnessDestination); err != nil {
- return errors.Wrap(err, "checking issuance destination")
+ vs2 := *vs
+ vs2.destPos = 0
+ if err = checkValidDest(&vs2, e.WitnessDestination); err != nil {
+ return errors.Wrap(err, "checking cross-chain input destination")
}
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:
+ 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")
}
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(),
)
}
-
vs2 := *vs
vs2.destPos = 0
if err = checkValidDest(&vs2, e.WitnessDestination); err != nil {
}
dest = ref.WitnessDestination
- case *bc.Issuance:
+ case *bc.CrossChainInput:
if vs.Position != 0 {
- return errors.Wrapf(ErrPosition, "invalid position %d for issuance source", vs.Position)
+ return errors.Wrapf(ErrPosition, "invalid position %d for cross-chain input source", vs.Position)
}
dest = ref.WitnessDestination
dest = ref.WitnessDestinations[vs.Position]
default:
- return errors.Wrapf(bc.ErrEntryType, "value source is %T, should be coinbase, issuance, spend, or mux", e)
+ return errors.Wrapf(bc.ErrEntryType, "value source is %T, should be coinbase, cross-chain input, spend, or mux", e)
}
if dest.Ref == nil || *dest.Ref != vstate.entryID {
}
src = ref.Source
+ case *bc.VoteOutput:
+ if vd.Position != 0 {
+ return errors.Wrapf(ErrPosition, "invalid position %d for output destination", vd.Position)
+ }
+ src = ref.Source
+
case *bc.Retirement:
if vd.Position != 0 {
return errors.Wrapf(ErrPosition, "invalid position %d for retirement destination", vd.Position)
continue
}
- intraChainSpentOutput, err := tx.IntraChainOutput(*spend.SpentOutputId)
+ code := []byte{}
+ outputEntry, err := tx.Entry(*spend.SpentOutputId)
if err != nil {
return err
}
-
- if !segwit.IsP2WScript(intraChainSpentOutput.ControlProgram.Code) {
- return ErrNotStandardTx
- }
- }
-
- for _, id := range tx.ResultIds {
- e, ok := tx.Entries[*id]
- if !ok {
- return errors.Wrapf(bc.ErrMissingEntry, "id %x", id.Bytes())
- }
-
- var prog []byte
- switch e := e.(type) {
+ switch output := outputEntry.(type) {
case *bc.IntraChainOutput:
- if *e.Source.Value.AssetId != *consensus.BTMAssetID {
- continue
- }
- prog = e.ControlProgram.Code
-
- case *bc.CrossChainOutput:
- if *e.Source.Value.AssetId != *consensus.BTMAssetID {
- continue
- }
- prog = e.ControlProgram.Code
-
+ code = output.ControlProgram.Code
+ case *bc.VoteOutput:
+ code = output.ControlProgram.Code
default:
- continue
+ return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", id.Bytes(), outputEntry)
}
- if !segwit.IsP2WScript(prog) {
+ if !segwit.IsP2WScript(code) {
return ErrNotStandardTx
}
}
-
return nil
}