6 "github.com/blockchain/crypto/sha3pool"
7 "github.com/blockchain/errors"
8 "github.com/blockchain/protocol/bc"
9 "github.com/blockchain/protocol/vm"
12 func newBlockVMContext(block *bc.Block, prog []byte, args [][]byte) *vm.Context {
13 blockHash := block.ID.Bytes()
19 BlockHash: &blockHash,
20 BlockTimeMS: &block.TimestampMs,
21 NextConsensusProgram: &block.NextConsensusProgram,
25 func NewTxVMContext(tx *bc.Tx, entry bc.Entry, prog *bc.Program, args [][]byte) *vm.Context {
27 numResults = uint64(len(tx.ResultIds))
28 txData = tx.Data.Bytes()
29 entryID = bc.EntryID(entry) // TODO(bobg): pass this in, don't recompute it
39 switch e := entry.(type) {
41 anchored := tx.Entries[*e.WitnessAnchoredId]
42 if iss, ok := anchored.(*bc.Issuance); ok {
43 a1 := iss.Value.AssetId.Bytes()
45 amount = &iss.Value.Amount
49 a1 := e.Value.AssetId.Bytes()
51 amount = &e.Value.Amount
52 destPos = &e.WitnessDestination.Position
55 a2 := e.AnchorId.Bytes()
59 spentOutput := tx.Entries[*e.SpentOutputId].(*bc.Output)
60 a1 := spentOutput.Source.Value.AssetId.Bytes()
62 amount = &spentOutput.Source.Value.Amount
63 destPos = &e.WitnessDestination.Position
66 s := e.SpentOutputId.Bytes()
79 txSigHashFn := func() []byte {
81 hasher := sha3pool.Get256()
82 defer sha3pool.Put256(hasher)
84 entryID.WriteTo(hasher)
89 hashBytes := hash.Bytes()
90 txSigHash = &hashBytes
100 result := &vm.Context{
101 VMVersion: prog.VmVersion,
105 EntryID: entryID.Bytes(),
107 TxVersion: &tx.Version,
109 TxSigHash: txSigHashFn,
110 NumResults: &numResults,
113 MinTimeMS: &tx.MinTimeMs,
114 MaxTimeMS: &tx.MaxTimeMs,
115 EntryData: entryData,
119 SpentOutputID: spentOutputID,
120 CheckOutput: ec.checkOutput,
126 type entryContext struct {
128 entries map[bc.Hash]bc.Entry
131 func (ec *entryContext) checkOutput(index uint64, data []byte, amount uint64, assetID []byte, vmVersion uint64, code []byte, expansion bool) (bool, error) {
132 checkEntry := func(e bc.Entry) (bool, error) {
133 check := func(prog *bc.Program, value *bc.AssetAmount, dataHash *bc.Hash) bool {
134 return (prog.VmVersion == vmVersion &&
135 bytes.Equal(prog.Code, code) &&
136 bytes.Equal(value.AssetId.Bytes(), assetID) &&
137 value.Amount == amount &&
138 (len(data) == 0 || bytes.Equal(dataHash.Bytes(), data)))
141 switch e := e.(type) {
143 return check(e.ControlProgram, e.Source.Value, e.Data), nil
148 // The spec requires prog.Code to be the empty string only
149 // when !expansion. When expansion is true, we prepopulate
150 // prog.Code to give check() a freebie match.
152 // (The spec always requires prog.VmVersion to be zero.)
155 return check(&prog, e.Source.Value, e.Data), nil
158 return false, vm.ErrContext
161 checkMux := func(m *bc.Mux) (bool, error) {
162 if index >= uint64(len(m.WitnessDestinations)) {
163 return false, errors.Wrapf(vm.ErrBadValue, "index %d >= %d", index, len(m.WitnessDestinations))
165 eID := m.WitnessDestinations[index].Ref
166 e, ok := ec.entries[*eID]
168 return false, errors.Wrapf(bc.ErrMissingEntry, "entry for mux destination %d, id %x, not found", index, eID.Bytes())
173 switch e := ec.entry.(type) {
178 d, ok := ec.entries[*e.WitnessDestination.Ref]
180 return false, errors.Wrapf(bc.ErrMissingEntry, "entry for issuance destination %x not found", e.WitnessDestination.Ref.Bytes())
182 if m, ok := d.(*bc.Mux); ok {
186 return false, errors.Wrapf(vm.ErrBadValue, "index %d >= 1", index)
191 d, ok := ec.entries[*e.WitnessDestination.Ref]
193 return false, errors.Wrapf(bc.ErrMissingEntry, "entry for spend destination %x not found", e.WitnessDestination.Ref.Bytes())
195 if m, ok := d.(*bc.Mux); ok {
199 return false, errors.Wrapf(vm.ErrBadValue, "index %d >= 1", index)
204 return false, vm.ErrContext