6 "github.com/vapor/consensus/segwit"
7 "github.com/vapor/crypto/sha3pool"
8 "github.com/vapor/errors"
9 "github.com/vapor/protocol/bc"
10 "github.com/vapor/protocol/vm"
13 // NewTxVMContext generates the vm.Context for BVM
14 func NewTxVMContext(vs *validationState, entry bc.Entry, prog *bc.Program, args [][]byte) *vm.Context {
17 blockHeight = vs.block.BlockHeader.GetHeight()
18 numResults = uint64(len(tx.ResultIds))
19 entryID = bc.EntryID(entry) // TODO(bobg): pass this in, don't recompute it
27 switch e := entry.(type) {
28 case *bc.CrossChainInput:
29 mainchainOutput := tx.Entries[*e.MainchainOutputId].(*bc.IntraChainOutput)
30 a1 := mainchainOutput.Source.Value.AssetId.Bytes()
32 amount = &mainchainOutput.Source.Value.Amount
33 destPos = &e.WitnessDestination.Position
34 s := e.MainchainOutputId.Bytes()
38 spentOutput := tx.Entries[*e.SpentOutputId].(*bc.IntraChainOutput)
39 a1 := spentOutput.Source.Value.AssetId.Bytes()
41 amount = &spentOutput.Source.Value.Amount
42 destPos = &e.WitnessDestination.Position
43 s := e.SpentOutputId.Bytes()
47 voteOutput := tx.Entries[*e.SpentOutputId].(*bc.VoteOutput)
48 a1 := voteOutput.Source.Value.AssetId.Bytes()
50 amount = &voteOutput.Source.Value.Amount
51 destPos = &e.WitnessDestination.Position
52 s := e.SpentOutputId.Bytes()
58 txSigHashFn := func() []byte {
60 hasher := sha3pool.Get256()
61 defer sha3pool.Put256(hasher)
63 entryID.WriteTo(hasher)
68 hashBytes := hash.Bytes()
69 txSigHash = &hashBytes
79 result := &vm.Context{
80 VMVersion: prog.VmVersion,
81 Code: witnessProgram(prog.Code),
84 EntryID: entryID.Bytes(),
86 TxVersion: &tx.Version,
87 BlockHeight: &blockHeight,
89 TxSigHash: txSigHashFn,
90 NumResults: &numResults,
94 SpentOutputID: spentOutputID,
95 CheckOutput: ec.checkOutput,
101 func witnessProgram(prog []byte) []byte {
102 if segwit.IsP2WPKHScript(prog) {
103 if witnessProg, err := segwit.ConvertP2PKHSigProgram([]byte(prog)); err == nil {
106 } else if segwit.IsP2WSHScript(prog) {
107 if witnessProg, err := segwit.ConvertP2SHProgram([]byte(prog)); err == nil {
114 type entryContext struct {
116 entries map[bc.Hash]bc.Entry
119 func (ec *entryContext) checkOutput(index uint64, amount uint64, assetID []byte, vmVersion uint64, code []byte, expansion bool) (bool, error) {
120 checkEntry := func(e bc.Entry) (bool, error) {
121 check := func(prog *bc.Program, value *bc.AssetAmount) bool {
122 return (prog.VmVersion == vmVersion &&
123 bytes.Equal(prog.Code, code) &&
124 bytes.Equal(value.AssetId.Bytes(), assetID) &&
125 value.Amount == amount)
128 switch e := e.(type) {
129 case *bc.IntraChainOutput:
130 return check(e.ControlProgram, e.Source.Value), nil
133 return check(e.ControlProgram, e.Source.Value), nil
138 // The spec requires prog.Code to be the empty string only
139 // when !expansion. When expansion is true, we prepopulate
140 // prog.Code to give check() a freebie match.
142 // (The spec always requires prog.VmVersion to be zero.)
145 return check(&prog, e.Source.Value), nil
148 return false, vm.ErrContext
151 checkMux := func(m *bc.Mux) (bool, error) {
152 if index >= uint64(len(m.WitnessDestinations)) {
153 return false, errors.Wrapf(vm.ErrBadValue, "index %d >= %d", index, len(m.WitnessDestinations))
155 eID := m.WitnessDestinations[index].Ref
156 e, ok := ec.entries[*eID]
158 return false, errors.Wrapf(bc.ErrMissingEntry, "entry for mux destination %d, id %x, not found", index, eID.Bytes())
163 switch e := ec.entry.(type) {
168 d, ok := ec.entries[*e.WitnessDestination.Ref]
170 return false, errors.Wrapf(bc.ErrMissingEntry, "entry for spend destination %x not found", e.WitnessDestination.Ref.Bytes())
172 if m, ok := d.(*bc.Mux); ok {
176 return false, errors.Wrapf(vm.ErrBadValue, "index %d >= 1", index)
181 d, ok := ec.entries[*e.WitnessDestination.Ref]
183 return false, errors.Wrapf(bc.ErrMissingEntry, "entry for vetoInput destination %x not found", e.WitnessDestination.Ref.Bytes())
185 if m, ok := d.(*bc.Mux); ok {
189 return false, errors.Wrapf(vm.ErrBadValue, "index %d >= 1", index)
194 return false, vm.ErrContext