diff --git a/cli/server/server.go b/cli/server/server.go index b7290c4b0..d11c5ce7b 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -177,8 +177,7 @@ func dumpDB(ctx *cli.Context) error { buf := io.NewBufBinWriter() b.EncodeBinary(buf.BinWriter) bytes := buf.Bytes() - writer.WriteLE(uint32(len(bytes))) - writer.WriteLE(bytes) + writer.WriteVarBytes(bytes) if writer.Err != nil { return cli.NewExitError(err, 1) } diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index f9bcbb8e8..526ceaf6e 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -330,9 +330,11 @@ func contractCompile(ctx *cli.Context) error { Debug: ctx.Bool("debug"), } - if err := compiler.CompileAndSave(src, o); err != nil { + result, err := compiler.CompileAndSave(src, o) + if err != nil { return cli.NewExitError(err, 1) } + fmt.Println(hex.EncodeToString(result)) return nil } diff --git a/pkg/consensus/payload.go b/pkg/consensus/payload.go index 6740e9370..881d0bbf1 100644 --- a/pkg/consensus/payload.go +++ b/pkg/consensus/payload.go @@ -169,7 +169,7 @@ func (p Payload) EncodeBinaryUnsigned(w *io.BinWriter) { ww := io.NewBufBinWriter() p.message.EncodeBinary(ww.BinWriter) - w.WriteBytes(ww.Bytes()) + w.WriteVarBytes(ww.Bytes()) } // EncodeBinary implements io.Serializable interface. diff --git a/pkg/consensus/recovery_message.go b/pkg/consensus/recovery_message.go index 9ef2761b8..3a01a168e 100644 --- a/pkg/consensus/recovery_message.go +++ b/pkg/consensus/recovery_message.go @@ -100,7 +100,7 @@ func (p *changeViewCompact) EncodeBinary(w *io.BinWriter) { w.WriteLE(p.ValidatorIndex) w.WriteLE(p.OriginalViewNumber) w.WriteLE(p.Timestamp) - w.WriteBytes(p.InvocationScript) + w.WriteVarBytes(p.InvocationScript) } // DecodeBinary implements io.Serializable interface. @@ -116,7 +116,7 @@ func (p *commitCompact) EncodeBinary(w *io.BinWriter) { w.WriteLE(p.ViewNumber) w.WriteLE(p.ValidatorIndex) w.WriteBE(p.Signature) - w.WriteBytes(p.InvocationScript) + w.WriteVarBytes(p.InvocationScript) } // DecodeBinary implements io.Serializable interface. @@ -128,7 +128,7 @@ func (p *preparationCompact) DecodeBinary(r *io.BinReader) { // EncodeBinary implements io.Serializable interface. func (p *preparationCompact) EncodeBinary(w *io.BinWriter) { w.WriteLE(p.ValidatorIndex) - w.WriteBytes(p.InvocationScript) + w.WriteVarBytes(p.InvocationScript) } // AddPayload implements payload.RecoveryMessage interface. diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 21d5ebb5f..87d219125 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1508,7 +1508,7 @@ func (bc *Blockchain) verifyBlockWitnesses(block *Block, prevHeader *Header) err func hashAndIndexToBytes(h util.Uint256, index uint32) []byte { buf := io.NewBufBinWriter() - buf.WriteLE(h.BytesReverse()) + buf.WriteBytes(h.BytesReverse()) buf.WriteLE(index) return buf.Bytes() } diff --git a/pkg/core/blockchain_state.go b/pkg/core/blockchain_state.go index db13408f8..b2b00b030 100644 --- a/pkg/core/blockchain_state.go +++ b/pkg/core/blockchain_state.go @@ -69,7 +69,7 @@ func (state *BlockChainState) storeAsBlock(block *Block, sysFee uint32) error { if err != nil { return err } - buf.WriteLE(b) + buf.WriteBytes(b) if buf.Err != nil { return buf.Err } @@ -79,7 +79,7 @@ func (state *BlockChainState) storeAsBlock(block *Block, sysFee uint32) error { // storeAsCurrentBlock stores the given block witch prefix SYSCurrentBlock. func (state *BlockChainState) storeAsCurrentBlock(block *Block) error { buf := io.NewBufBinWriter() - buf.WriteLE(block.Hash().BytesReverse()) + buf.WriteBytes(block.Hash().BytesReverse()) buf.WriteLE(block.Index) return state.store.Put(storage.SYSCurrentBlock.Bytes(), buf.Bytes()) } diff --git a/pkg/core/contract_state.go b/pkg/core/contract_state.go index e3efdce27..2b3a32138 100644 --- a/pkg/core/contract_state.go +++ b/pkg/core/contract_state.go @@ -52,7 +52,7 @@ func (cs *ContractState) DecodeBinary(br *io.BinReader) { // EncodeBinary implements Serializable interface. func (cs *ContractState) EncodeBinary(bw *io.BinWriter) { - bw.WriteBytes(cs.Script) + bw.WriteVarBytes(cs.Script) bw.WriteArray(cs.ParamList) bw.WriteLE(cs.ReturnType) bw.WriteLE(cs.Properties) diff --git a/pkg/core/storage_item.go b/pkg/core/storage_item.go index 2e6166a8b..a78de51dc 100644 --- a/pkg/core/storage_item.go +++ b/pkg/core/storage_item.go @@ -53,7 +53,7 @@ func deleteStorageItemInStore(s storage.Store, scripthash util.Uint160, key []by // EncodeBinary implements Serializable interface. func (si *StorageItem) EncodeBinary(w *io.BinWriter) { - w.WriteBytes(si.Value) + w.WriteVarBytes(si.Value) w.WriteLE(si.IsConst) } diff --git a/pkg/core/transaction/attribute.go b/pkg/core/transaction/attribute.go index 45883cb18..3cd92d333 100644 --- a/pkg/core/transaction/attribute.go +++ b/pkg/core/transaction/attribute.go @@ -55,18 +55,18 @@ func (attr *Attribute) EncodeBinary(bw *io.BinWriter) { bw.WriteLE(&attr.Usage) switch attr.Usage { case ECDH02, ECDH03: - bw.WriteLE(attr.Data[1:]) + bw.WriteBytes(attr.Data[1:]) case Description, Remark, Remark1, Remark2, Remark3, Remark4, Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11, Remark12, Remark13, Remark14, Remark15: - bw.WriteBytes(attr.Data) + bw.WriteVarBytes(attr.Data) case DescriptionURL: var urllen = uint8(len(attr.Data)) bw.WriteLE(urllen) fallthrough case Script, ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6, Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15: - bw.WriteLE(attr.Data) + bw.WriteBytes(attr.Data) default: bw.Err = fmt.Errorf("failed encoding TX attribute usage: 0x%2x", attr.Usage) } diff --git a/pkg/core/transaction/invocation.go b/pkg/core/transaction/invocation.go index f303ddf16..6276a1a28 100644 --- a/pkg/core/transaction/invocation.go +++ b/pkg/core/transaction/invocation.go @@ -45,7 +45,7 @@ func (tx *InvocationTX) DecodeBinary(br *io.BinReader) { // EncodeBinary implements Serializable interface. func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) { - bw.WriteBytes(tx.Script) + bw.WriteVarBytes(tx.Script) if tx.Version >= 1 { bw.WriteLE(tx.Gas) } diff --git a/pkg/core/transaction/publish.go b/pkg/core/transaction/publish.go index e46ce6a56..131a4ac9a 100644 --- a/pkg/core/transaction/publish.go +++ b/pkg/core/transaction/publish.go @@ -51,7 +51,7 @@ func (tx *PublishTX) DecodeBinary(br *io.BinReader) { // EncodeBinary implements Serializable interface. func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) { - bw.WriteBytes(tx.Script) + bw.WriteVarBytes(tx.Script) bw.WriteVarUint(uint64(len(tx.ParamList))) for _, param := range tx.ParamList { bw.WriteLE(uint8(param)) diff --git a/pkg/core/transaction/register.go b/pkg/core/transaction/register.go index 5ca940ac3..e8d754eb3 100644 --- a/pkg/core/transaction/register.go +++ b/pkg/core/transaction/register.go @@ -49,6 +49,6 @@ func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) { bw.WriteString(tx.Name) bw.WriteLE(tx.Amount) bw.WriteLE(tx.Precision) - bw.WriteLE(tx.Owner.Bytes()) + bw.WriteBytes(tx.Owner.Bytes()) bw.WriteLE(tx.Admin) } diff --git a/pkg/core/transaction/state_descriptor.go b/pkg/core/transaction/state_descriptor.go index 087ea5baf..c5d3cc958 100644 --- a/pkg/core/transaction/state_descriptor.go +++ b/pkg/core/transaction/state_descriptor.go @@ -33,7 +33,7 @@ func (s *StateDescriptor) DecodeBinary(r *io.BinReader) { // EncodeBinary implements Serializable interface. func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) { w.WriteLE(s.Type) - w.WriteBytes(s.Key) - w.WriteBytes(s.Value) + w.WriteVarBytes(s.Key) + w.WriteVarBytes(s.Value) w.WriteString(s.Field) } diff --git a/pkg/core/transaction/witness.go b/pkg/core/transaction/witness.go index 8640dca74..bdbecb80d 100644 --- a/pkg/core/transaction/witness.go +++ b/pkg/core/transaction/witness.go @@ -23,8 +23,8 @@ func (w *Witness) DecodeBinary(br *io.BinReader) { // EncodeBinary implements Serializable interface. func (w *Witness) EncodeBinary(bw *io.BinWriter) { - bw.WriteBytes(w.InvocationScript) - bw.WriteBytes(w.VerificationScript) + bw.WriteVarBytes(w.InvocationScript) + bw.WriteVarBytes(w.VerificationScript) } // MarshalJSON implements the json marshaller interface. diff --git a/pkg/crypto/keys/publickey.go b/pkg/crypto/keys/publickey.go index 8bae4a652..dad925ffd 100644 --- a/pkg/crypto/keys/publickey.go +++ b/pkg/crypto/keys/publickey.go @@ -219,7 +219,7 @@ func (p *PublicKey) DecodeBinary(r *io.BinReader) { // EncodeBinary encodes a PublicKey to the given BinWriter. func (p *PublicKey) EncodeBinary(w *io.BinWriter) { - w.WriteLE(p.Bytes()) + w.WriteBytes(p.Bytes()) } // Signature returns a NEO-specific hash of the key. diff --git a/pkg/io/binaryBufWriter.go b/pkg/io/binaryBufWriter.go index 31ba262ac..7015082e1 100644 --- a/pkg/io/binaryBufWriter.go +++ b/pkg/io/binaryBufWriter.go @@ -19,6 +19,11 @@ func NewBufBinWriter() *BufBinWriter { return &BufBinWriter{BinWriter: NewBinWriterFromIO(b), buf: b} } +// Len returns the number of bytes of the unread portion of the buffer. +func (bw *BufBinWriter) Len() int { + return bw.buf.Len() +} + // Bytes returns resulting buffer and makes future writes return an error. func (bw *BufBinWriter) Bytes() []byte { if bw.Err != nil { diff --git a/pkg/io/binaryWriter.go b/pkg/io/binaryWriter.go index 19086e255..b5aee0d0c 100644 --- a/pkg/io/binaryWriter.go +++ b/pkg/io/binaryWriter.go @@ -93,13 +93,18 @@ func (w *BinWriter) WriteVarUint(val uint64) { } -// WriteBytes writes a variable length byte array into the underlying io.Writer. +// WriteBytes writes a variable byte into the underlying io.Writer without prefix. func (w *BinWriter) WriteBytes(b []byte) { + w.WriteLE(b) +} + +// WriteVarBytes writes a variable length byte array into the underlying io.Writer. +func (w *BinWriter) WriteVarBytes(b []byte) { w.WriteVarUint(uint64(len(b))) w.WriteLE(b) } // WriteString writes a variable length string into the underlying io.Writer. func (w *BinWriter) WriteString(s string) { - w.WriteBytes([]byte(s)) + w.WriteVarBytes([]byte(s)) } diff --git a/pkg/io/binaryrw_test.go b/pkg/io/binaryrw_test.go index 672e14ffd..213b394e0 100644 --- a/pkg/io/binaryrw_test.go +++ b/pkg/io/binaryrw_test.go @@ -53,6 +53,13 @@ func TestWriteBE(t *testing.T) { assert.Equal(t, val, readval) } +func TestBufBinWriter_Len(t *testing.T) { + val := []byte{0xde} + bw := NewBufBinWriter() + bw.WriteLE(val) + require.Equal(t, 1, bw.Len()) +} + func TestWriterErrHandling(t *testing.T) { var badio = &badRW{} bw := NewBinWriterFromIO(badio) @@ -62,7 +69,7 @@ func TestWriterErrHandling(t *testing.T) { bw.WriteLE(uint32(0)) bw.WriteBE(uint32(0)) bw.WriteVarUint(0) - bw.WriteBytes([]byte{0x55, 0xaa}) + bw.WriteVarBytes([]byte{0x55, 0xaa}) bw.WriteString("neo") assert.NotNil(t, bw.Err) } diff --git a/pkg/network/payload/merkleblock.go b/pkg/network/payload/merkleblock.go index dad96f305..67142c2b4 100644 --- a/pkg/network/payload/merkleblock.go +++ b/pkg/network/payload/merkleblock.go @@ -31,5 +31,5 @@ func (m *MerkleBlock) EncodeBinary(bw *io.BinWriter) { bw.WriteVarUint(uint64(m.TxCount)) bw.WriteArray(m.Hashes) - bw.WriteBytes(m.Flags) + bw.WriteVarBytes(m.Flags) } diff --git a/pkg/network/payload/version.go b/pkg/network/payload/version.go index ead40df01..b221eef63 100644 --- a/pkg/network/payload/version.go +++ b/pkg/network/payload/version.go @@ -73,7 +73,7 @@ func (p *Version) EncodeBinary(br *io.BinWriter) { br.WriteLE(p.Port) br.WriteLE(p.Nonce) - br.WriteBytes(p.UserAgent) + br.WriteVarBytes(p.UserAgent) br.WriteLE(p.StartHeight) br.WriteLE(&p.Relay) } diff --git a/pkg/vm/compiler/analysis.go b/pkg/vm/compiler/analysis.go index 2824938bf..f57abf85d 100644 --- a/pkg/vm/compiler/analysis.go +++ b/pkg/vm/compiler/analysis.go @@ -1,10 +1,10 @@ package compiler import ( + "fmt" "go/ast" "go/constant" "go/types" - "log" "golang.org/x/tools/go/loader" ) @@ -19,7 +19,7 @@ var ( ) // typeAndValueForField returns a zero initialized typeAndValue for the given type.Var. -func typeAndValueForField(fld *types.Var) types.TypeAndValue { +func typeAndValueForField(fld *types.Var) (types.TypeAndValue, error) { switch t := fld.Type().(type) { case *types.Basic: switch t.Kind() { @@ -27,22 +27,22 @@ func typeAndValueForField(fld *types.Var) types.TypeAndValue { return types.TypeAndValue{ Type: t, Value: constant.MakeInt64(0), - } + }, nil case types.String: return types.TypeAndValue{ Type: t, Value: constant.MakeString(""), - } + }, nil case types.Bool, types.UntypedBool: return types.TypeAndValue{ Type: t, Value: constant.MakeBool(false), - } + }, nil default: - log.Fatalf("could not initialize struct field %s to zero, type: %s", fld.Name(), t) + return types.TypeAndValue{}, fmt.Errorf("could not initialize struct field %s to zero, type: %s", fld.Name(), t) } } - return types.TypeAndValue{} + return types.TypeAndValue{}, nil } // countGlobals counts the global variables in the program to add @@ -69,7 +69,7 @@ func isIdentBool(ident *ast.Ident) bool { } // makeBoolFromIdent creates a bool type from an *ast.Ident. -func makeBoolFromIdent(ident *ast.Ident, tinfo *types.Info) types.TypeAndValue { +func makeBoolFromIdent(ident *ast.Ident, tinfo *types.Info) (types.TypeAndValue, error) { var b bool switch ident.Name { case "true": @@ -77,12 +77,12 @@ func makeBoolFromIdent(ident *ast.Ident, tinfo *types.Info) types.TypeAndValue { case "false": b = false default: - log.Fatalf("givent identifier cannot be converted to a boolean => %s", ident.Name) + return types.TypeAndValue{}, fmt.Errorf("givent identifier cannot be converted to a boolean => %s", ident.Name) } return types.TypeAndValue{ Type: tinfo.ObjectOf(ident).Type(), Value: constant.MakeBool(b), - } + }, nil } // resolveEntryPoint returns the function declaration of the entrypoint and the corresponding file. diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index f54d0f844..c850b8dbc 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -1,18 +1,18 @@ package compiler import ( - "bytes" "encoding/binary" + "fmt" "go/ast" "go/constant" "go/token" "go/types" - "log" "sort" "strconv" "strings" "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/vm" ) @@ -24,7 +24,7 @@ type codegen struct { buildInfo *buildInfo // prog holds the output buffer. - prog *bytes.Buffer + prog *io.BufBinWriter // Type information. typeInfo *types.Info @@ -56,66 +56,73 @@ func (c *codegen) pc() int { } func (c *codegen) emitLoadConst(t types.TypeAndValue) { + if c.prog.Err != nil { + return + } switch typ := t.Type.Underlying().(type) { case *types.Basic: switch typ.Kind() { case types.Int, types.UntypedInt, types.Uint: val, _ := constant.Int64Val(t.Value) - emitInt(c.prog, val) + emitInt(c.prog.BinWriter, val) case types.String, types.UntypedString: val := constant.StringVal(t.Value) - emitString(c.prog, val) + emitString(c.prog.BinWriter, val) case types.Bool, types.UntypedBool: val := constant.BoolVal(t.Value) - emitBool(c.prog, val) + emitBool(c.prog.BinWriter, val) case types.Byte: val, _ := constant.Int64Val(t.Value) b := byte(val) - emitBytes(c.prog, []byte{b}) + emitBytes(c.prog.BinWriter, []byte{b}) default: - log.Fatalf("compiler doesn't know how to convert this basic type: %v", t) + c.prog.Err = fmt.Errorf("compiler doesn't know how to convert this basic type: %v", t) + return } default: - log.Fatalf("compiler doesn't know how to convert this constant: %v", t) + c.prog.Err = fmt.Errorf("compiler doesn't know how to convert this constant: %v", t) + return } } func (c *codegen) emitLoadLocal(name string) { pos := c.scope.loadLocal(name) if pos < 0 { - log.Fatalf("cannot load local variable with position: %d", pos) + c.prog.Err = fmt.Errorf("cannot load local variable with position: %d", pos) + return } c.emitLoadLocalPos(pos) } func (c *codegen) emitLoadLocalPos(pos int) { - emitOpcode(c.prog, vm.DUPFROMALTSTACK) - emitInt(c.prog, int64(pos)) - emitOpcode(c.prog, vm.PICKITEM) + emitOpcode(c.prog.BinWriter, vm.DUPFROMALTSTACK) + emitInt(c.prog.BinWriter, int64(pos)) + emitOpcode(c.prog.BinWriter, vm.PICKITEM) } func (c *codegen) emitStoreLocal(pos int) { - emitOpcode(c.prog, vm.DUPFROMALTSTACK) + emitOpcode(c.prog.BinWriter, vm.DUPFROMALTSTACK) if pos < 0 { - log.Fatalf("invalid position to store local: %d", pos) + c.prog.Err = fmt.Errorf("invalid position to store local: %d", pos) + return } - emitInt(c.prog, int64(pos)) - emitInt(c.prog, 2) - emitOpcode(c.prog, vm.ROLL) - emitOpcode(c.prog, vm.SETITEM) + emitInt(c.prog.BinWriter, int64(pos)) + emitInt(c.prog.BinWriter, 2) + emitOpcode(c.prog.BinWriter, vm.ROLL) + emitOpcode(c.prog.BinWriter, vm.SETITEM) } func (c *codegen) emitLoadField(i int) { - emitInt(c.prog, int64(i)) - emitOpcode(c.prog, vm.PICKITEM) + emitInt(c.prog.BinWriter, int64(i)) + emitOpcode(c.prog.BinWriter, vm.PICKITEM) } func (c *codegen) emitStoreStructField(i int) { - emitInt(c.prog, int64(i)) - emitOpcode(c.prog, vm.ROT) - emitOpcode(c.prog, vm.SETITEM) + emitInt(c.prog.BinWriter, int64(i)) + emitOpcode(c.prog.BinWriter, vm.ROT) + emitOpcode(c.prog.BinWriter, vm.SETITEM) } // convertGlobals traverses the AST and only converts global declarations. @@ -155,9 +162,9 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) { // All globals copied into the scope of the function need to be added // to the stack size of the function. - emitInt(c.prog, f.stackSize()+countGlobals(file)) - emitOpcode(c.prog, vm.NEWARRAY) - emitOpcode(c.prog, vm.TOALTSTACK) + emitInt(c.prog.BinWriter, f.stackSize()+countGlobals(file)) + emitOpcode(c.prog.BinWriter, vm.NEWARRAY) + emitOpcode(c.prog.BinWriter, vm.TOALTSTACK) // We need to handle methods, which in Go, is just syntactic sugar. // The method receiver will be passed in as first argument. @@ -171,7 +178,8 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) { // Currently only method receives for struct types is supported. _, ok := c.typeInfo.Defs[ident].Type().Underlying().(*types.Struct) if !ok { - log.Fatal("method receives for non-struct types is not yet supported") + c.prog.Err = fmt.Errorf("method receives for non-struct types is not yet supported") + return } l := c.scope.newLocal(ident.Name) c.emitStoreLocal(l) @@ -194,13 +202,16 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) { // If this function returns the void (no return stmt) we will cleanup its junk on the stack. if !hasReturnStmt(decl) { - emitOpcode(c.prog, vm.FROMALTSTACK) - emitOpcode(c.prog, vm.DROP) - emitOpcode(c.prog, vm.RET) + emitOpcode(c.prog.BinWriter, vm.FROMALTSTACK) + emitOpcode(c.prog.BinWriter, vm.DROP) + emitOpcode(c.prog.BinWriter, vm.RET) } } func (c *codegen) Visit(node ast.Node) ast.Visitor { + if c.prog.Err != nil { + return nil + } switch n := node.(type) { // General declarations. @@ -248,7 +259,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.emitStoreStructField(i) // store the field } default: - log.Fatal("nested selector assigns not supported yet") + c.prog.Err = fmt.Errorf("nested selector assigns not supported yet") + return nil } // Assignments to index expressions. @@ -262,7 +274,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { indexStr := t.Index.(*ast.BasicLit).Value index, err := strconv.Atoi(indexStr) if err != nil { - log.Fatal("failed to convert slice index to integer") + c.prog.Err = fmt.Errorf("failed to convert slice index to integer") + return nil } c.emitStoreStructField(index) } @@ -271,7 +284,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case *ast.ReturnStmt: if len(n.Results) > 1 { - log.Fatal("multiple returns not supported.") + c.prog.Err = fmt.Errorf("multiple returns not supported") + return nil } l := c.newLabel() @@ -281,9 +295,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { ast.Walk(c, n.Results[0]) } - emitOpcode(c.prog, vm.FROMALTSTACK) - emitOpcode(c.prog, vm.DROP) // Cleanup the stack. - emitOpcode(c.prog, vm.RET) + emitOpcode(c.prog.BinWriter, vm.FROMALTSTACK) + emitOpcode(c.prog.BinWriter, vm.DROP) // Cleanup the stack. + emitOpcode(c.prog.BinWriter, vm.RET) return nil case *ast.IfStmt: @@ -293,13 +307,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { if n.Cond != nil { ast.Walk(c, n.Cond) - emitJmp(c.prog, vm.JMPIFNOT, int16(lElse)) + emitJmp(c.prog.BinWriter, vm.JMPIFNOT, int16(lElse)) } c.setLabel(lIf) ast.Walk(c, n.Body) if n.Else != nil { - emitJmp(c.prog, vm.JMP, int16(lElseEnd)) + emitJmp(c.prog.BinWriter, vm.JMP, int16(lElseEnd)) } c.setLabel(lElse) @@ -315,7 +329,12 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case *ast.Ident: if isIdentBool(n) { - c.emitLoadConst(makeBoolFromIdent(n, c.typeInfo)) + value, err := makeBoolFromIdent(n, c.typeInfo) + if err != nil { + c.prog.Err = err + return nil + } + c.emitLoadConst(value) } else { c.emitLoadLocal(n.Name) } @@ -339,8 +358,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { for i := ln - 1; i >= 0; i-- { c.emitLoadConst(c.typeInfo.Types[n.Elts[i]]) } - emitInt(c.prog, int64(ln)) - emitOpcode(c.prog, vm.PACK) + emitInt(c.prog.BinWriter, int64(ln)) + emitOpcode(c.prog.BinWriter, vm.PACK) return nil } @@ -355,13 +374,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { switch n.Op { case token.LAND: ast.Walk(c, n.X) - emitJmp(c.prog, vm.JMPIFNOT, int16(len(c.l)-1)) + emitJmp(c.prog.BinWriter, vm.JMPIFNOT, int16(len(c.l)-1)) ast.Walk(c, n.Y) return nil case token.LOR: ast.Walk(c, n.X) - emitJmp(c.prog, vm.JMPIF, int16(len(c.l)-3)) + emitJmp(c.prog.BinWriter, vm.JMPIF, int16(len(c.l)-3)) ast.Walk(c, n.Y) return nil @@ -386,24 +405,24 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case n.Op == token.ADD: // VM has separate opcodes for number and string concatenation if isStringType(tinfo.Type) { - emitOpcode(c.prog, vm.CAT) + emitOpcode(c.prog.BinWriter, vm.CAT) } else { - emitOpcode(c.prog, vm.ADD) + emitOpcode(c.prog.BinWriter, vm.ADD) } case n.Op == token.EQL: // VM has separate opcodes for number and string equality if isStringType(c.typeInfo.Types[n.X].Type) { - emitOpcode(c.prog, vm.EQUAL) + emitOpcode(c.prog.BinWriter, vm.EQUAL) } else { - emitOpcode(c.prog, vm.NUMEQUAL) + emitOpcode(c.prog.BinWriter, vm.NUMEQUAL) } case n.Op == token.NEQ: // VM has separate opcodes for number and string equality if isStringType(c.typeInfo.Types[n.X].Type) { - emitOpcode(c.prog, vm.EQUAL) - emitOpcode(c.prog, vm.NOT) + emitOpcode(c.prog.BinWriter, vm.EQUAL) + emitOpcode(c.prog.BinWriter, vm.NOT) } else { - emitOpcode(c.prog, vm.NUMNOTEQUAL) + emitOpcode(c.prog.BinWriter, vm.NUMNOTEQUAL) } default: c.convertToken(n.Op) @@ -423,7 +442,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case *ast.Ident: f, ok = c.funcs[fun.Name] if !ok && !isBuiltin { - log.Fatalf("could not resolve function %s", fun.Name) + c.prog.Err = fmt.Errorf("could not resolve function %s", fun.Name) + return nil } case *ast.SelectorExpr: // If this is a method call we need to walk the AST to load the struct locally. @@ -439,7 +459,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { // @FIXME this could cause runtime errors. f.selector = fun.X.(*ast.Ident) if !ok { - log.Fatalf("could not resolve function %s", fun.Sel.Name) + c.prog.Err = fmt.Errorf("could not resolve function %s", fun.Sel.Name) + return nil } case *ast.ArrayType: // For now we will assume that there is only 1 argument passed which @@ -457,14 +478,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { // Do not swap for builtin functions. if !isBuiltin { if numArgs == 2 { - emitOpcode(c.prog, vm.SWAP) + emitOpcode(c.prog.BinWriter, vm.SWAP) } else if numArgs == 3 { - emitInt(c.prog, 2) - emitOpcode(c.prog, vm.XSWAP) + emitInt(c.prog.BinWriter, 2) + emitOpcode(c.prog.BinWriter, vm.XSWAP) } else { for i := 1; i < numArgs; i++ { - emitInt(c.prog, int64(i)) - emitOpcode(c.prog, vm.ROLL) + emitInt(c.prog.BinWriter, int64(i)) + emitOpcode(c.prog.BinWriter, vm.ROLL) } } } @@ -478,7 +499,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case isSyscall(f): c.convertSyscall(f.selector.Name, f.name) default: - emitCall(c.prog, vm.CALL, int16(f.label)) + emitCall(c.prog.BinWriter, vm.CALL, int16(f.label)) } return nil @@ -493,7 +514,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.emitLoadField(i) // load the field } default: - log.Fatal("nested selectors not supported yet") + c.prog.Err = fmt.Errorf("nested selectors not supported yet") + return nil } return nil @@ -507,13 +529,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case token.ADD: // +10 == 10, no need to do anything in this case case token.SUB: - emitOpcode(c.prog, vm.NEGATE) + emitOpcode(c.prog.BinWriter, vm.NEGATE) case token.NOT: - emitOpcode(c.prog, vm.NOT) + emitOpcode(c.prog.BinWriter, vm.NOT) case token.XOR: - emitOpcode(c.prog, vm.INVERT) + emitOpcode(c.prog.BinWriter, vm.INVERT) default: - log.Fatalf("invalid unary operator: %s", n.Op) + c.prog.Err = fmt.Errorf("invalid unary operator: %s", n.Op) + return nil } return nil @@ -542,7 +565,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.emitLoadField(int(val)) default: ast.Walk(c, n.Index) - emitOpcode(c.prog, vm.PICKITEM) // just pickitem here + emitOpcode(c.prog.BinWriter, vm.PICKITEM) // just pickitem here } return nil @@ -560,14 +583,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { ast.Walk(c, n.Cond) // Jump if the condition is false - emitJmp(c.prog, vm.JMPIFNOT, int16(fend)) + emitJmp(c.prog.BinWriter, vm.JMPIFNOT, int16(fend)) // Walk body followed by the iterator (post stmt). ast.Walk(c, n.Body) ast.Walk(c, n.Post) // Jump back to condition. - emitJmp(c.prog, vm.JMP, int16(fstart)) + emitJmp(c.prog.BinWriter, vm.JMP, int16(fstart)) c.setLabel(fend) return nil @@ -586,13 +609,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { func (c *codegen) convertSyscall(api, name string) { api, ok := syscalls[api][name] if !ok { - log.Fatalf("unknown VM syscall api: %s", name) + c.prog.Err = fmt.Errorf("unknown VM syscall api: %s", name) + return } - emitSyscall(c.prog, api) + emitSyscall(c.prog.BinWriter, api) // This NOP instruction is basically not needed, but if we do, we have a // one to one matching avm file with neo-python which is very nice for debugging. - emitOpcode(c.prog, vm.NOP) + emitOpcode(c.prog.BinWriter, vm.NOP) } func (c *codegen) convertBuiltin(expr *ast.CallExpr) { @@ -609,32 +633,32 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { arg := expr.Args[0] typ := c.typeInfo.Types[arg].Type if isStringType(typ) { - emitOpcode(c.prog, vm.SIZE) + emitOpcode(c.prog.BinWriter, vm.SIZE) } else { - emitOpcode(c.prog, vm.ARRAYSIZE) + emitOpcode(c.prog.BinWriter, vm.ARRAYSIZE) } case "append": arg := expr.Args[0] typ := c.typeInfo.Types[arg].Type if isByteArrayType(typ) { - emitOpcode(c.prog, vm.CAT) + emitOpcode(c.prog.BinWriter, vm.CAT) } else { - emitOpcode(c.prog, vm.SWAP) - emitOpcode(c.prog, vm.DUP) - emitOpcode(c.prog, vm.PUSH2) - emitOpcode(c.prog, vm.XSWAP) - emitOpcode(c.prog, vm.APPEND) + emitOpcode(c.prog.BinWriter, vm.SWAP) + emitOpcode(c.prog.BinWriter, vm.DUP) + emitOpcode(c.prog.BinWriter, vm.PUSH2) + emitOpcode(c.prog.BinWriter, vm.XSWAP) + emitOpcode(c.prog.BinWriter, vm.APPEND) } case "SHA256": - emitOpcode(c.prog, vm.SHA256) + emitOpcode(c.prog.BinWriter, vm.SHA256) case "SHA1": - emitOpcode(c.prog, vm.SHA1) + emitOpcode(c.prog.BinWriter, vm.SHA1) case "Hash256": - emitOpcode(c.prog, vm.HASH256) + emitOpcode(c.prog.BinWriter, vm.HASH256) case "Hash160": - emitOpcode(c.prog, vm.HASH160) + emitOpcode(c.prog.BinWriter, vm.HASH160) case "Equals": - emitOpcode(c.prog, vm.EQUAL) + emitOpcode(c.prog.BinWriter, vm.EQUAL) case "FromAddress": // We can be sure that this is a ast.BasicLit just containing a simple // address string. Note that the string returned from calling Value will @@ -643,10 +667,11 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { addressStr = strings.Replace(addressStr, "\"", "", 2) uint160, err := crypto.Uint160DecodeAddress(addressStr) if err != nil { - log.Fatal(err) + c.prog.Err = err + return } bytes := uint160.Bytes() - emitBytes(c.prog, bytes) + emitBytes(c.prog.BinWriter, bytes) } } @@ -657,7 +682,7 @@ func (c *codegen) convertByteArray(lit *ast.CompositeLit) { val, _ := constant.Int64Val(t.Value) buf[i] = byte(val) } - emitBytes(c.prog, buf) + emitBytes(c.prog.BinWriter, buf) } func (c *codegen) convertStruct(lit *ast.CompositeLit) { @@ -665,13 +690,14 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) { // the positions of its variables. strct, ok := c.typeInfo.TypeOf(lit).Underlying().(*types.Struct) if !ok { - log.Fatalf("the given literal is not of type struct: %v", lit) + c.prog.Err = fmt.Errorf("the given literal is not of type struct: %v", lit) + return } - emitOpcode(c.prog, vm.NOP) - emitInt(c.prog, int64(strct.NumFields())) - emitOpcode(c.prog, vm.NEWSTRUCT) - emitOpcode(c.prog, vm.TOALTSTACK) + emitOpcode(c.prog.BinWriter, vm.NOP) + emitInt(c.prog.BinWriter, int64(strct.NumFields())) + emitOpcode(c.prog.BinWriter, vm.NEWSTRUCT) + emitOpcode(c.prog.BinWriter, vm.TOALTSTACK) // We need to locally store all the fields, even if they are not initialized. // We will initialize all fields to their "zero" value. @@ -696,61 +722,66 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) { continue } - typeAndVal := typeAndValueForField(sField) + typeAndVal, err := typeAndValueForField(sField) + if err != nil { + c.prog.Err = err + return + } c.emitLoadConst(typeAndVal) c.emitStoreLocal(i) } - emitOpcode(c.prog, vm.FROMALTSTACK) + emitOpcode(c.prog.BinWriter, vm.FROMALTSTACK) } func (c *codegen) convertToken(tok token.Token) { switch tok { case token.ADD_ASSIGN: - emitOpcode(c.prog, vm.ADD) + emitOpcode(c.prog.BinWriter, vm.ADD) case token.SUB_ASSIGN: - emitOpcode(c.prog, vm.SUB) + emitOpcode(c.prog.BinWriter, vm.SUB) case token.MUL_ASSIGN: - emitOpcode(c.prog, vm.MUL) + emitOpcode(c.prog.BinWriter, vm.MUL) case token.QUO_ASSIGN: - emitOpcode(c.prog, vm.DIV) + emitOpcode(c.prog.BinWriter, vm.DIV) case token.ADD: - emitOpcode(c.prog, vm.ADD) + emitOpcode(c.prog.BinWriter, vm.ADD) case token.SUB: - emitOpcode(c.prog, vm.SUB) + emitOpcode(c.prog.BinWriter, vm.SUB) case token.MUL: - emitOpcode(c.prog, vm.MUL) + emitOpcode(c.prog.BinWriter, vm.MUL) case token.QUO: - emitOpcode(c.prog, vm.DIV) + emitOpcode(c.prog.BinWriter, vm.DIV) case token.LSS: - emitOpcode(c.prog, vm.LT) + emitOpcode(c.prog.BinWriter, vm.LT) case token.LEQ: - emitOpcode(c.prog, vm.LTE) + emitOpcode(c.prog.BinWriter, vm.LTE) case token.GTR: - emitOpcode(c.prog, vm.GT) + emitOpcode(c.prog.BinWriter, vm.GT) case token.GEQ: - emitOpcode(c.prog, vm.GTE) + emitOpcode(c.prog.BinWriter, vm.GTE) case token.EQL: - emitOpcode(c.prog, vm.NUMEQUAL) + emitOpcode(c.prog.BinWriter, vm.NUMEQUAL) case token.NEQ: - emitOpcode(c.prog, vm.NUMNOTEQUAL) + emitOpcode(c.prog.BinWriter, vm.NUMNOTEQUAL) case token.DEC: - emitOpcode(c.prog, vm.DEC) + emitOpcode(c.prog.BinWriter, vm.DEC) case token.INC: - emitOpcode(c.prog, vm.INC) + emitOpcode(c.prog.BinWriter, vm.INC) case token.NOT: - emitOpcode(c.prog, vm.NOT) + emitOpcode(c.prog.BinWriter, vm.NOT) case token.AND: - emitOpcode(c.prog, vm.AND) + emitOpcode(c.prog.BinWriter, vm.AND) case token.OR: - emitOpcode(c.prog, vm.OR) + emitOpcode(c.prog.BinWriter, vm.OR) case token.SHL: - emitOpcode(c.prog, vm.SHL) + emitOpcode(c.prog.BinWriter, vm.SHL) case token.SHR: - emitOpcode(c.prog, vm.SHR) + emitOpcode(c.prog.BinWriter, vm.SHR) case token.XOR: - emitOpcode(c.prog, vm.XOR) + emitOpcode(c.prog.BinWriter, vm.XOR) default: - log.Fatalf("compiler could not convert token: %s", tok) + c.prog.Err = fmt.Errorf("compiler could not convert token: %s", tok) + return } } @@ -761,11 +792,11 @@ func (c *codegen) newFunc(decl *ast.FuncDecl) *funcScope { } // CodeGen compiles the program to bytecode. -func CodeGen(info *buildInfo) (*bytes.Buffer, error) { +func CodeGen(info *buildInfo) ([]byte, error) { pkg := info.program.Package(info.initialPackage) c := &codegen{ buildInfo: info, - prog: new(bytes.Buffer), + prog: io.NewBufBinWriter(), l: []int{}, funcs: map[string]*funcScope{}, typeInfo: &pkg.Info, @@ -774,7 +805,8 @@ func CodeGen(info *buildInfo) (*bytes.Buffer, error) { // Resolve the entrypoint of the program. main, mainFile := resolveEntryPoint(mainIdent, pkg) if main == nil { - log.Fatal("could not find func main. Did you forget to declare it?") + c.prog.Err = fmt.Errorf("could not find func main. Did you forget to declare it? ") + return []byte{}, c.prog.Err } funUsage := analyzeFuncUsage(info.program.AllPackages) @@ -815,9 +847,12 @@ func CodeGen(info *buildInfo) (*bytes.Buffer, error) { } } - c.writeJumps() - - return c.prog, nil + if c.prog.Err != nil { + return nil, c.prog.Err + } + buf := c.prog.Bytes() + c.writeJumps(buf) + return buf, nil } func (c *codegen) resolveFuncDecls(f *ast.File) { @@ -831,8 +866,7 @@ func (c *codegen) resolveFuncDecls(f *ast.File) { } } -func (c *codegen) writeJumps() { - b := c.prog.Bytes() +func (c *codegen) writeJumps(b []byte) { for i, op := range b { j := i + 1 switch vm.Instruction(op) { diff --git a/pkg/vm/compiler/compiler.go b/pkg/vm/compiler/compiler.go index 5ead0d34a..6875409fe 100644 --- a/pkg/vm/compiler/compiler.go +++ b/pkg/vm/compiler/compiler.go @@ -2,7 +2,6 @@ package compiler import ( "bytes" - "encoding/hex" "fmt" "go/ast" "go/build" @@ -10,7 +9,6 @@ import ( "go/types" "io" "io/ioutil" - "log" "os" "strings" @@ -60,7 +58,7 @@ func Compile(r io.Reader) ([]byte, error) { return nil, err } - return buf.Bytes(), nil + return buf, nil } type archive struct { @@ -69,9 +67,9 @@ type archive struct { } // CompileAndSave will compile and save the file to disk. -func CompileAndSave(src string, o *Options) error { +func CompileAndSave(src string, o *Options) ([]byte, error) { if !strings.HasSuffix(src, ".go") { - return fmt.Errorf("%s is not a Go file", src) + return nil, fmt.Errorf("%s is not a Go file", src) } o.Outfile = strings.TrimSuffix(o.Outfile, fmt.Sprintf(".%s", fileExt)) if len(o.Outfile) == 0 { @@ -82,17 +80,15 @@ func CompileAndSave(src string, o *Options) error { } b, err := ioutil.ReadFile(src) if err != nil { - return err + return nil, err } b, err = Compile(bytes.NewReader(b)) if err != nil { - return fmt.Errorf("error while trying to compile smart contract file: %v", err) + return nil, fmt.Errorf("error while trying to compile smart contract file: %v", err) } - log.Println(hex.EncodeToString(b)) - out := fmt.Sprintf("%s.%s", o.Outfile, o.Ext) - return ioutil.WriteFile(out, b, os.ModePerm) + return b, ioutil.WriteFile(out, b, os.ModePerm) } func gopath() string { @@ -102,7 +98,3 @@ func gopath() string { } return gopath } - -func init() { - log.SetFlags(0) -} diff --git a/pkg/vm/compiler/emit.go b/pkg/vm/compiler/emit.go index 92be632f8..6e1834e5a 100644 --- a/pkg/vm/compiler/emit.go +++ b/pkg/vm/compiler/emit.go @@ -1,105 +1,114 @@ package compiler import ( - "bytes" "encoding/binary" "errors" "fmt" - "io" "math/big" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm" ) -func emit(w *bytes.Buffer, instr vm.Instruction, b []byte) error { - if err := w.WriteByte(byte(instr)); err != nil { - return err - } - _, err := w.Write(b) - return err +// emit a VM Instruction with data to the given buffer. +func emit(w *io.BinWriter, instr vm.Instruction, b []byte) { + emitOpcode(w, instr) + w.WriteBytes(b) } -func emitOpcode(w io.ByteWriter, instr vm.Instruction) error { - return w.WriteByte(byte(instr)) +// emitOpcode emits a single VM Instruction the given buffer. +func emitOpcode(w *io.BinWriter, instr vm.Instruction) { + w.WriteLE(byte(instr)) } -func emitBool(w io.ByteWriter, ok bool) error { +// emitBool emits a bool type the given buffer. +func emitBool(w *io.BinWriter, ok bool) { if ok { - return emitOpcode(w, vm.PUSHT) + emitOpcode(w, vm.PUSHT) + return } - return emitOpcode(w, vm.PUSHF) + emitOpcode(w, vm.PUSHF) } -func emitInt(w *bytes.Buffer, i int64) error { - if i == -1 { - return emitOpcode(w, vm.PUSHM1) - } - if i == 0 { - return emitOpcode(w, vm.PUSHF) - } - if i > 0 && i < 16 { +// emitInt emits a int type to the given buffer. +func emitInt(w *io.BinWriter, i int64) { + switch { + case i == -1: + emitOpcode(w, vm.PUSHM1) + return + case i == 0: + emitOpcode(w, vm.PUSHF) + return + case i > 0 && i < 16: val := vm.Instruction(int(vm.PUSH1) - 1 + int(i)) - return emitOpcode(w, val) + emitOpcode(w, val) + return } bInt := big.NewInt(i) val := util.ArrayReverse(bInt.Bytes()) - return emitBytes(w, val) + emitBytes(w, val) } -func emitString(w *bytes.Buffer, s string) error { - return emitBytes(w, []byte(s)) +// emitString emits a string to the given buffer. +func emitString(w *io.BinWriter, s string) { + emitBytes(w, []byte(s)) } -func emitBytes(w *bytes.Buffer, b []byte) error { - var ( - err error - n = len(b) - ) +// emitBytes emits a byte array to the given buffer. +func emitBytes(w *io.BinWriter, b []byte) { + n := len(b) switch { case n <= int(vm.PUSHBYTES75): - return emit(w, vm.Instruction(n), b) + emit(w, vm.Instruction(n), b) + return case n < 0x100: - err = emit(w, vm.PUSHDATA1, []byte{byte(n)}) + emit(w, vm.PUSHDATA1, []byte{byte(n)}) case n < 0x10000: buf := make([]byte, 2) binary.LittleEndian.PutUint16(buf, uint16(n)) - err = emit(w, vm.PUSHDATA2, buf) + emit(w, vm.PUSHDATA2, buf) default: buf := make([]byte, 4) binary.LittleEndian.PutUint32(buf, uint32(n)) - err = emit(w, vm.PUSHDATA4, buf) + emit(w, vm.PUSHDATA4, buf) + if w.Err != nil { + return + } } - if err != nil { - return err - } - _, err = w.Write(b) - return err + + w.WriteBytes(b) } -func emitSyscall(w *bytes.Buffer, api string) error { +// emitSyscall emits the syscall API to the given buffer. +// Syscall API string cannot be 0. +func emitSyscall(w *io.BinWriter, api string) { if len(api) == 0 { - return errors.New("syscall api cannot be of length 0") + w.Err = errors.New("syscall api cannot be of length 0") + return } buf := make([]byte, len(api)+1) buf[0] = byte(len(api)) copy(buf[1:], api) - return emit(w, vm.SYSCALL, buf) + emit(w, vm.SYSCALL, buf) } -func emitCall(w *bytes.Buffer, instr vm.Instruction, label int16) error { - return emitJmp(w, instr, label) +// emitCall emits a call Instruction with label to the given buffer. +func emitCall(w *io.BinWriter, instr vm.Instruction, label int16) { + emitJmp(w, instr, label) } -func emitJmp(w *bytes.Buffer, instr vm.Instruction, label int16) error { +// emitJmp emits a jump Instruction along with label to the given buffer. +func emitJmp(w *io.BinWriter, instr vm.Instruction, label int16) { if !isInstrJmp(instr) { - return fmt.Errorf("opcode %s is not a jump or call type", instr) + w.Err = fmt.Errorf("opcode %s is not a jump or call type", instr) + return } buf := make([]byte, 2) binary.LittleEndian.PutUint16(buf, uint16(label)) - return emit(w, instr, buf) + emit(w, instr, buf) } func isInstrJmp(instr vm.Instruction) bool { diff --git a/pkg/vm/serialization.go b/pkg/vm/serialization.go index 81562df0d..5434e8b5a 100644 --- a/pkg/vm/serialization.go +++ b/pkg/vm/serialization.go @@ -44,13 +44,13 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) { switch t := item.(type) { case *ByteArrayItem: w.WriteLE(byte(byteArrayT)) - w.WriteBytes(t.value) + w.WriteVarBytes(t.value) case *BoolItem: w.WriteLE(byte(booleanT)) w.WriteLE(t.value) case *BigIntegerItem: w.WriteLE(byte(integerT)) - w.WriteBytes(t.Bytes()) + w.WriteVarBytes(t.Bytes()) case *InteropItem: w.Err = errors.New("not supported") case *ArrayItem, *StructItem: