parent
6767bb5446
commit
973d39eceb
32 changed files with 0 additions and 1677 deletions
|
@ -1,62 +0,0 @@
|
|||
# Package - Wire
|
||||
|
||||
|
||||
The neo wire package will implement the network protocol displayed here: http://docs.neo.org/en-us/network/network-protocol.html
|
||||
|
||||
This package will act as a standalone package.
|
||||
|
||||
# Responsibility
|
||||
|
||||
This package will solely be responsible for Encoding and decoding a Message.
|
||||
It will return a Messager interface, which means that the caller of the package will need to type assert it to the appropriate type.
|
||||
|
||||
# Usage
|
||||
|
||||
## Write Message
|
||||
|
||||
expectedIP := "127.0.0.1"
|
||||
expectedPort := 8333
|
||||
tcpAddrMe := &net.TCPAddr{IP: net.ParseIP(expectedIP), Port: expectedPort}
|
||||
message, err := NewVersionMessage(tcpAddrMe, 0, true, defaultVersion)
|
||||
|
||||
conn := new(bytes.Buffer)
|
||||
if err := WriteMessage(con, Production, message); err != nil {
|
||||
// handle Error
|
||||
}
|
||||
|
||||
## Read Message
|
||||
|
||||
readmsg, err := ReadMessage(conn, Production)
|
||||
|
||||
if err != nil {
|
||||
// Log error
|
||||
}
|
||||
version := readmsg.(*VersionMessage)
|
||||
|
||||
## RoadMap
|
||||
|
||||
These below commands are left to implement.
|
||||
|
||||
[ x ] CMDVersion (Tests added)
|
||||
[ x ] CMDVerack (Tests Added)
|
||||
[ x ] CMDGetAddr(Tests Added)
|
||||
[ x ] CMDAddr (Tests Added)
|
||||
[ x ] CMDGetHeaders (Tests Added)
|
||||
[ x ] CMDHeaders (Tests Added)
|
||||
[ x ] CMDGetBlocks (Tests Added)
|
||||
[ x ] CMDInv (Tests Added)
|
||||
[ x ] CMDGetData (Tests Added)
|
||||
[ x ] CMDBlock (Tests Added)
|
||||
[ x ] CMDTX // Each tx implments the messager interface
|
||||
[ ] CMDConsensus
|
||||
|
||||
## Notes
|
||||
|
||||
Please not that this package will do sanity checks on the fields, however it will not verify if any of the items are valid for the current state of the system. Please see `Responbilities`.
|
||||
|
||||
The difference between Encode/Decode and EncodePayload/DecodePayload, is the parameter type.
|
||||
In most cases, Encode/Decode is just a convenience method.
|
||||
# Contributors
|
||||
|
||||
When modifying this package, please ensure that it does not depend on any other package and that it conforms to the Single Responsibility Principle. If you see somewhere in the current implementation that does not do this, then please tell me.
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package wire
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/command"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
// Base is everything in the message except the payload
|
||||
type Base struct {
|
||||
Magic uint32
|
||||
CMD command.Type
|
||||
PayloadLength uint32
|
||||
Checksum uint32
|
||||
}
|
||||
|
||||
// DecodeBase will decode an io.Reader into a Base object
|
||||
// Note, That there is no EncodeBase, As the header is implicitly inferred from the message on Encode To send
|
||||
func (h *Base) DecodeBase(r io.Reader) (io.Reader, error) {
|
||||
br := &util.BinReader{R: r}
|
||||
|
||||
br.Read(&h.Magic)
|
||||
|
||||
var cmd [12]byte
|
||||
br.Read(&cmd)
|
||||
h.CMD = command.Type(cmdByteArrayToString(cmd))
|
||||
|
||||
br.Read(&h.PayloadLength)
|
||||
br.Read(&h.Checksum)
|
||||
return br.R, br.Err
|
||||
}
|
||||
|
||||
func cmdByteArrayToString(cmd [command.Size]byte) string {
|
||||
buf := []byte{}
|
||||
for i := 0; i < command.Size; i++ {
|
||||
if cmd[i] != 0 {
|
||||
buf = append(buf, cmd[i])
|
||||
}
|
||||
}
|
||||
return string(buf)
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
package wire
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction"
|
||||
checksum "github.com/CityOfZion/neo-go/pkg/wire/util/Checksum"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/command"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/protocol"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
// Messager is implemented by any object that can
|
||||
// Encode and Decode Payloads
|
||||
type Messager interface {
|
||||
// EncodePayload takes a message payload and encodes it
|
||||
EncodePayload(w io.Writer) error
|
||||
// DecodePayload takes an io.Reader and decodes it into
|
||||
// a message payload
|
||||
DecodePayload(r io.Reader) error
|
||||
// Command returns the assosciated command type
|
||||
Command() command.Type
|
||||
}
|
||||
|
||||
const (
|
||||
// Magic + cmd + length + checksum
|
||||
minMsgSize = 4 + 12 + 4 + 4
|
||||
)
|
||||
|
||||
var (
|
||||
errChecksumMismatch = errors.New("checksum mismatch")
|
||||
)
|
||||
|
||||
// WriteMessage will write a message to a given io.Writer
|
||||
func WriteMessage(w io.Writer, magic protocol.Magic, message Messager) error {
|
||||
bw := &util.BinWriter{W: w}
|
||||
bw.Write(magic)
|
||||
bw.Write(cmdToByteArray(message.Command()))
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := message.EncodePayload(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
payloadLen := uint32(buf.Len())
|
||||
checksum := checksum.FromBytes(buf.Bytes())
|
||||
|
||||
bw.Write(payloadLen)
|
||||
bw.Write(checksum)
|
||||
|
||||
bw.WriteBigEnd(buf.Bytes())
|
||||
|
||||
return bw.Err
|
||||
}
|
||||
|
||||
// ReadMessage will read a message from a given io.Reader
|
||||
func ReadMessage(r io.Reader, magic protocol.Magic) (Messager, error) {
|
||||
|
||||
byt := make([]byte, minMsgSize)
|
||||
|
||||
if _, err := io.ReadFull(r, byt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(byt)
|
||||
|
||||
var header Base
|
||||
_, err := header.DecodeBase(reader)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New("Error decoding into the header base")
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
_, err = io.CopyN(buf, r, int64(header.PayloadLength))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Compare the checksum of the payload.
|
||||
if !checksum.Compare(header.Checksum, buf.Bytes()) {
|
||||
return nil, errChecksumMismatch
|
||||
}
|
||||
switch header.CMD {
|
||||
case command.Version:
|
||||
v := &payload.VersionMessage{}
|
||||
err := v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.Verack:
|
||||
v, err := payload.NewVerackMessage()
|
||||
err = v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.Inv:
|
||||
v, err := payload.NewInvMessage(0)
|
||||
err = v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.GetAddr:
|
||||
v, err := payload.NewGetAddrMessage()
|
||||
err = v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.Addr:
|
||||
v, err := payload.NewAddrMessage()
|
||||
err = v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.Block:
|
||||
v, err := payload.NewBlockMessage()
|
||||
err = v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.GetBlocks:
|
||||
v, err := payload.NewGetBlocksMessage([]util.Uint256{}, util.Uint256{})
|
||||
err = v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.GetData:
|
||||
v, err := payload.NewGetDataMessage(payload.InvTypeTx)
|
||||
err = v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.GetHeaders:
|
||||
v, err := payload.NewGetHeadersMessage([]util.Uint256{}, util.Uint256{})
|
||||
err = v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.Headers:
|
||||
v, err := payload.NewHeadersMessage()
|
||||
err = v.DecodePayload(buf)
|
||||
return v, err
|
||||
case command.TX:
|
||||
reader := bufio.NewReader(buf)
|
||||
tx, err := transaction.FromReader(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload.NewTXMessage(tx)
|
||||
}
|
||||
return nil, errors.New("Unknown Message found")
|
||||
|
||||
}
|
||||
|
||||
func cmdToByteArray(cmd command.Type) [command.Size]byte {
|
||||
cmdLen := len(cmd)
|
||||
if cmdLen > command.Size {
|
||||
panic("exceeded command max length of size 12")
|
||||
}
|
||||
|
||||
// The command can have max 12 bytes, rest is filled with 0.
|
||||
b := [command.Size]byte{}
|
||||
for i := 0; i < cmdLen; i++ {
|
||||
b[i] = cmd[i]
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/protocol"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// This is quite hard to test because the message uses time.Now()
|
||||
// TODO: Test each field expect time.Now(), just make sure it is a uint32
|
||||
func TestWriteMessageLen(t *testing.T) {
|
||||
|
||||
expectedIP := "127.0.0.1"
|
||||
expectedPort := 8333
|
||||
tcpAddrMe := &net.TCPAddr{IP: net.ParseIP(expectedIP), Port: expectedPort}
|
||||
|
||||
message, err := payload.NewVersionMessage(tcpAddrMe, 0, true, protocol.DefaultVersion, protocol.UserAgent, 100, protocol.NodePeerService)
|
||||
if err != nil {
|
||||
assert.Fail(t, err.Error())
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := WriteMessage(buf, protocol.MainNet, message); err != nil {
|
||||
assert.Fail(t, err.Error())
|
||||
}
|
||||
assert.Equal(t, 60, len(buf.Bytes()))
|
||||
}
|
||||
func TestReadMessage(t *testing.T) {
|
||||
|
||||
expectedIP := "127.0.0.1"
|
||||
expectedPort := 8333
|
||||
tcpAddrMe := &net.TCPAddr{IP: net.ParseIP(expectedIP), Port: expectedPort}
|
||||
|
||||
message, err := payload.NewVersionMessage(tcpAddrMe, 23, true, protocol.DefaultVersion, protocol.UserAgent, 100, protocol.NodePeerService)
|
||||
if err != nil {
|
||||
assert.Fail(t, err.Error())
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
if err := WriteMessage(buf, protocol.MainNet, message); err != nil {
|
||||
assert.Fail(t, err.Error())
|
||||
}
|
||||
|
||||
readmsg, err := ReadMessage(buf, protocol.MainNet)
|
||||
|
||||
if err != nil {
|
||||
assert.Fail(t, err.Error())
|
||||
}
|
||||
version := readmsg.(*payload.VersionMessage)
|
||||
assert.Equal(t, 23, int(version.StartHeight))
|
||||
// If MessageReading was unsuccessfull it will return a nil object
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package payload
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/command"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction"
|
||||
)
|
||||
|
||||
// TXMessage represents a transaction message on the neo-network
|
||||
type TXMessage struct {
|
||||
Tx transaction.Transactioner
|
||||
}
|
||||
|
||||
//NewTXMessage returns a new tx object
|
||||
func NewTXMessage(tx transaction.Transactioner) (*TXMessage, error) {
|
||||
|
||||
Tx := &TXMessage{tx}
|
||||
return Tx, nil
|
||||
}
|
||||
|
||||
// DecodePayload Implements Messager interface
|
||||
func (t *TXMessage) DecodePayload(r io.Reader) error {
|
||||
return t.Tx.Decode(r)
|
||||
}
|
||||
|
||||
// EncodePayload Implements messager interface
|
||||
func (t *TXMessage) EncodePayload(w io.Writer) error {
|
||||
return t.Tx.Encode(w)
|
||||
}
|
||||
|
||||
// Command Implements messager interface
|
||||
func (t *TXMessage) Command() command.Type {
|
||||
return command.TX
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
// Attribute represents a Transaction attribute.
|
||||
type Attribute struct {
|
||||
Usage AttrUsage
|
||||
Data []byte
|
||||
}
|
||||
|
||||
var errMaxData = errors.New("max Size of Attribute reached")
|
||||
|
||||
const maxAttrSize = 65535
|
||||
|
||||
// Encode encodes the given Attribute into the binary writer
|
||||
func (a *Attribute) Encode(bw *util.BinWriter) {
|
||||
if len(a.Data) > maxAttrSize {
|
||||
bw.Err = errMaxData
|
||||
return
|
||||
}
|
||||
bw.Write(uint8(a.Usage))
|
||||
|
||||
if a.Usage == ContractHash || a.Usage == Vote || (a.Usage >= Hash1 && a.Usage <= Hash15) {
|
||||
bw.Write(a.Data[:32])
|
||||
} else if a.Usage == ECDH02 || a.Usage == ECDH03 {
|
||||
bw.Write(a.Data[1:33])
|
||||
} else if a.Usage == Script {
|
||||
bw.Write(a.Data[:20])
|
||||
} else if a.Usage == DescriptionURL || a.Usage == Description || a.Usage >= Remark {
|
||||
bw.VarUint(uint64(len(a.Data)))
|
||||
bw.Write(a.Data)
|
||||
} else {
|
||||
bw.Write(a.Data)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Decode decodes the binary reader into an Attribute object
|
||||
func (a *Attribute) Decode(br *util.BinReader) {
|
||||
br.Read(&a.Usage)
|
||||
if a.Usage == ContractHash || a.Usage == Vote || a.Usage >= Hash1 && a.Usage <= Hash15 {
|
||||
a.Data = make([]byte, 32)
|
||||
br.Read(&a.Data)
|
||||
} else if a.Usage == ECDH02 || a.Usage == ECDH03 {
|
||||
a.Data = make([]byte, 32)
|
||||
br.Read(&a.Data)
|
||||
} else if a.Usage == Script {
|
||||
a.Data = make([]byte, 20)
|
||||
br.Read(&a.Data)
|
||||
} else if a.Usage == DescriptionURL || a.Usage == Description || a.Usage >= Remark {
|
||||
lenData := br.VarUint()
|
||||
a.Data = make([]byte, lenData)
|
||||
br.Read(&a.Data)
|
||||
} else {
|
||||
br.Read(&a.Data)
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import "github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
|
||||
// Input represents a Transaction input.
|
||||
type Input struct {
|
||||
// The hash of the previous transaction.
|
||||
PrevHash util.Uint256
|
||||
|
||||
// The index of the previous transaction.
|
||||
PrevIndex uint16
|
||||
}
|
||||
|
||||
//NewInput returns a transaction input object
|
||||
func NewInput(prevHash util.Uint256, prevIndex uint16) *Input {
|
||||
return &Input{
|
||||
prevHash,
|
||||
prevIndex,
|
||||
}
|
||||
}
|
||||
|
||||
// Encode encodes the given input into a binary writer
|
||||
func (i *Input) Encode(bw *util.BinWriter) {
|
||||
bw.Write(i.PrevHash)
|
||||
bw.Write(i.PrevIndex)
|
||||
}
|
||||
|
||||
// Decode decodes a binary reader into an input object
|
||||
func (i *Input) Decode(br *util.BinReader) {
|
||||
br.Read(&i.PrevHash)
|
||||
br.Read(&i.PrevIndex)
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import "github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
|
||||
// Output represents a transaction output in the neo-network
|
||||
type Output struct {
|
||||
// The NEO asset id used in the transaction.
|
||||
AssetID util.Uint256
|
||||
|
||||
// Amount of AssetType send or received.
|
||||
Amount int64
|
||||
|
||||
// The address of the remittee.
|
||||
ScriptHash util.Uint160
|
||||
}
|
||||
|
||||
//NewOutput returns an output object
|
||||
func NewOutput(assetID util.Uint256, Amount int64, ScriptHash util.Uint160) *Output {
|
||||
return &Output{
|
||||
assetID,
|
||||
Amount,
|
||||
ScriptHash,
|
||||
}
|
||||
}
|
||||
|
||||
// Encode encodes the Output into a binary writer
|
||||
func (o *Output) Encode(bw *util.BinWriter) {
|
||||
bw.Write(o.AssetID)
|
||||
bw.Write(o.Amount)
|
||||
bw.Write(o.ScriptHash)
|
||||
}
|
||||
|
||||
// Decode decodes a binary reader into an output object
|
||||
func (o *Output) Decode(br *util.BinReader) {
|
||||
br.Read(&o.AssetID)
|
||||
br.Read(&o.Amount)
|
||||
br.Read(&o.ScriptHash)
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
//Witness represents a Witness object in a neo transaction
|
||||
type Witness struct {
|
||||
InvocationScript []byte
|
||||
VerificationScript []byte
|
||||
}
|
||||
|
||||
// Encode encodes a Witness into a binary writer
|
||||
func (s *Witness) Encode(bw *util.BinWriter) error {
|
||||
|
||||
bw.VarUint(uint64(len(s.InvocationScript)))
|
||||
bw.Write(s.InvocationScript)
|
||||
|
||||
bw.VarUint(uint64(len(s.VerificationScript)))
|
||||
bw.Write(s.VerificationScript)
|
||||
|
||||
return bw.Err
|
||||
}
|
||||
|
||||
// Decode decodes a binary reader into a Witness object
|
||||
func (s *Witness) Decode(br *util.BinReader) error {
|
||||
|
||||
lenb := br.VarUint()
|
||||
s.InvocationScript = make([]byte, lenb)
|
||||
br.Read(s.InvocationScript)
|
||||
|
||||
lenb = br.VarUint()
|
||||
s.VerificationScript = make([]byte, lenb)
|
||||
br.Read(s.VerificationScript)
|
||||
|
||||
return br.Err
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package transaction
|
||||
|
||||
// AssetType represent a NEO asset type
|
||||
type AssetType uint8
|
||||
|
||||
// Valid asset types.
|
||||
const (
|
||||
CreditFlag AssetType = 0x40
|
||||
DutyFlag AssetType = 0x80
|
||||
GoverningToken AssetType = 0x00
|
||||
UtilityToken AssetType = 0x01
|
||||
Currency AssetType = 0x08
|
||||
Share AssetType = DutyFlag | 0x10
|
||||
Invoice AssetType = DutyFlag | 0x18
|
||||
Token AssetType = CreditFlag | 0x20
|
||||
)
|
|
@ -1,49 +0,0 @@
|
|||
package transaction
|
||||
|
||||
// AttrUsage represents an attribute usage on the neo network
|
||||
type AttrUsage uint8
|
||||
|
||||
// List of valid attribute usages.
|
||||
const (
|
||||
ContractHash AttrUsage = 0x00
|
||||
ECDH02 AttrUsage = 0x02
|
||||
ECDH03 AttrUsage = 0x03
|
||||
Script AttrUsage = 0x20
|
||||
Vote AttrUsage = 0x30
|
||||
CertURL AttrUsage = 0x80
|
||||
DescriptionURL AttrUsage = 0x81
|
||||
Description AttrUsage = 0x90
|
||||
|
||||
Hash1 AttrUsage = 0xa1
|
||||
Hash2 AttrUsage = 0xa2
|
||||
Hash3 AttrUsage = 0xa3
|
||||
Hash4 AttrUsage = 0xa4
|
||||
Hash5 AttrUsage = 0xa5
|
||||
Hash6 AttrUsage = 0xa6
|
||||
Hash7 AttrUsage = 0xa7
|
||||
Hash8 AttrUsage = 0xa8
|
||||
Hash9 AttrUsage = 0xa9
|
||||
Hash10 AttrUsage = 0xaa
|
||||
Hash11 AttrUsage = 0xab
|
||||
Hash12 AttrUsage = 0xac
|
||||
Hash13 AttrUsage = 0xad
|
||||
Hash14 AttrUsage = 0xae
|
||||
Hash15 AttrUsage = 0xaf
|
||||
|
||||
Remark AttrUsage = 0xf0
|
||||
Remark1 AttrUsage = 0xf1
|
||||
Remark2 AttrUsage = 0xf2
|
||||
Remark3 AttrUsage = 0xf3
|
||||
Remark4 AttrUsage = 0xf4
|
||||
Remark5 AttrUsage = 0xf5
|
||||
Remark6 AttrUsage = 0xf6
|
||||
Remark7 AttrUsage = 0xf7
|
||||
Remark8 AttrUsage = 0xf8
|
||||
Remark9 AttrUsage = 0xf9
|
||||
Remark10 AttrUsage = 0xfa
|
||||
Remark11 AttrUsage = 0xfb
|
||||
Remark12 AttrUsage = 0xfc
|
||||
Remark13 AttrUsage = 0xfd
|
||||
Remark14 AttrUsage = 0xfe
|
||||
Remark15 AttrUsage = 0xff
|
||||
)
|
|
@ -1,202 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
type encodeExclusiveFields func(bw *util.BinWriter)
|
||||
type decodeExclusiveFields func(br *util.BinReader)
|
||||
|
||||
// Transactioner is the interface that will unite the
|
||||
// transaction types. Each transaction will implement this interface
|
||||
// and so wil be a transactioner
|
||||
type Transactioner interface {
|
||||
Encode(w io.Writer) error
|
||||
Decode(r io.Reader) error
|
||||
BaseTx() *Base
|
||||
ID() (util.Uint256, error)
|
||||
}
|
||||
|
||||
// Base transaction is the template for all other transactions
|
||||
// It contains all of the shared fields between transactions and
|
||||
// the additional encodeExclusive and decodeExclusive methods, which
|
||||
// can be overwitten in the other transactions to encode the non shared fields
|
||||
type Base struct {
|
||||
Type types.TX
|
||||
Version version.TX
|
||||
Inputs []*Input
|
||||
Outputs []*Output
|
||||
Attributes []*Attribute
|
||||
Witnesses []*Witness
|
||||
Hash util.Uint256
|
||||
encodeExclusive encodeExclusiveFields
|
||||
decodeExclusive decodeExclusiveFields
|
||||
}
|
||||
|
||||
func createBaseTransaction(typ types.TX, ver version.TX) *Base {
|
||||
return &Base{
|
||||
Type: typ,
|
||||
Version: ver,
|
||||
Inputs: []*Input{},
|
||||
Outputs: []*Output{},
|
||||
Attributes: []*Attribute{},
|
||||
Witnesses: []*Witness{},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Decode implements the transactioner interface
|
||||
func (b *Base) Decode(r io.Reader) error {
|
||||
br := &util.BinReader{R: r}
|
||||
return b.DecodePayload(br)
|
||||
}
|
||||
|
||||
// Encode implements the transactioner interface
|
||||
func (b *Base) Encode(w io.Writer) error {
|
||||
bw := &util.BinWriter{W: w}
|
||||
b.EncodePayload(bw)
|
||||
return bw.Err
|
||||
}
|
||||
|
||||
//EncodePayload implements the Messager interface
|
||||
func (b *Base) EncodePayload(bw *util.BinWriter) {
|
||||
b.encodeHashableFields(bw)
|
||||
|
||||
lenWitnesses := uint64(len(b.Witnesses))
|
||||
bw.VarUint(lenWitnesses)
|
||||
|
||||
for _, witness := range b.Witnesses {
|
||||
witness.Encode(bw)
|
||||
}
|
||||
}
|
||||
|
||||
// DecodePayload implements the messager interface
|
||||
func (b *Base) DecodePayload(br *util.BinReader) error {
|
||||
b.decodeHashableFields(br)
|
||||
|
||||
lenWitnesses := br.VarUint()
|
||||
|
||||
b.Witnesses = make([]*Witness, lenWitnesses)
|
||||
for i := 0; i < int(lenWitnesses); i++ {
|
||||
b.Witnesses[i] = &Witness{}
|
||||
b.Witnesses[i].Decode(br)
|
||||
}
|
||||
|
||||
if br.Err != nil {
|
||||
return br.Err
|
||||
}
|
||||
|
||||
return b.createHash()
|
||||
}
|
||||
|
||||
func (b *Base) encodeHashableFields(bw *util.BinWriter) {
|
||||
b.Type.Encode(bw)
|
||||
b.Version.Encode(bw)
|
||||
|
||||
b.encodeExclusive(bw)
|
||||
|
||||
lenAttrs := uint64(len(b.Attributes))
|
||||
lenInputs := uint64(len(b.Inputs))
|
||||
lenOutputs := uint64(len(b.Outputs))
|
||||
|
||||
bw.VarUint(lenAttrs)
|
||||
for _, attr := range b.Attributes {
|
||||
attr.Encode(bw)
|
||||
}
|
||||
|
||||
bw.VarUint(lenInputs)
|
||||
for _, input := range b.Inputs {
|
||||
input.Encode(bw)
|
||||
}
|
||||
|
||||
bw.VarUint(lenOutputs)
|
||||
for _, output := range b.Outputs {
|
||||
output.Encode(bw)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Base) decodeHashableFields(br *util.BinReader) {
|
||||
b.Type.Decode(br)
|
||||
|
||||
b.Version.Decode(br)
|
||||
|
||||
b.decodeExclusive(br)
|
||||
|
||||
lenAttrs := br.VarUint()
|
||||
b.Attributes = make([]*Attribute, lenAttrs)
|
||||
for i := 0; i < int(lenAttrs); i++ {
|
||||
|
||||
b.Attributes[i] = &Attribute{}
|
||||
b.Attributes[i].Decode(br)
|
||||
}
|
||||
|
||||
lenInputs := br.VarUint()
|
||||
|
||||
b.Inputs = make([]*Input, lenInputs)
|
||||
for i := 0; i < int(lenInputs); i++ {
|
||||
b.Inputs[i] = &Input{}
|
||||
b.Inputs[i].Decode(br)
|
||||
}
|
||||
|
||||
lenOutputs := br.VarUint()
|
||||
b.Outputs = make([]*Output, lenOutputs)
|
||||
for i := 0; i < int(lenOutputs); i++ {
|
||||
b.Outputs[i] = &Output{}
|
||||
b.Outputs[i].Decode(br)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// AddInput adds an input to the transaction
|
||||
func (b *Base) AddInput(i *Input) {
|
||||
b.Inputs = append(b.Inputs, i)
|
||||
}
|
||||
|
||||
// AddOutput adds an output to the transaction
|
||||
func (b *Base) AddOutput(o *Output) {
|
||||
b.Outputs = append(b.Outputs, o)
|
||||
}
|
||||
|
||||
// AddAttribute adds an attribute to the transaction
|
||||
func (b *Base) AddAttribute(a *Attribute) {
|
||||
b.Attributes = append(b.Attributes, a)
|
||||
}
|
||||
|
||||
// AddWitness adds a witness object to the transaction
|
||||
func (b *Base) AddWitness(w *Witness) {
|
||||
b.Witnesses = append(b.Witnesses, w)
|
||||
}
|
||||
|
||||
func (b *Base) createHash() error {
|
||||
|
||||
hash, err := util.CalculateHash(b.encodeHashableFields)
|
||||
b.Hash = hash
|
||||
return err
|
||||
}
|
||||
|
||||
// ID returns the TXID of the transaction
|
||||
func (b *Base) ID() (util.Uint256, error) {
|
||||
var emptyHash util.Uint256
|
||||
var err error
|
||||
if b.Hash == emptyHash {
|
||||
err = b.createHash()
|
||||
}
|
||||
return b.Hash, err
|
||||
}
|
||||
|
||||
// Bytes returns the raw bytes of the tx
|
||||
func (b *Base) Bytes() []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
b.Encode(buf)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// BaseTx returns the Base object in a transaction
|
||||
func (b *Base) BaseTx() *Base {
|
||||
return b
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
//Claim represents a claim transaction on the neo network
|
||||
type Claim struct {
|
||||
*Base
|
||||
Claims []*Input
|
||||
}
|
||||
|
||||
//NewClaim returns a ClaimTransaction
|
||||
func NewClaim(ver version.TX) *Claim {
|
||||
basicTrans := createBaseTransaction(types.Contract, ver)
|
||||
|
||||
claim := &Claim{}
|
||||
claim.Base = basicTrans
|
||||
claim.encodeExclusive = claim.encodeExcl
|
||||
claim.decodeExclusive = claim.decodeExcl
|
||||
return claim
|
||||
}
|
||||
|
||||
func (c *Claim) encodeExcl(bw *util.BinWriter) {
|
||||
|
||||
bw.VarUint(uint64(len(c.Claims)))
|
||||
for _, claim := range c.Claims {
|
||||
claim.Encode(bw)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Claim) decodeExcl(br *util.BinReader) {
|
||||
lenClaims := br.VarUint()
|
||||
|
||||
c.Claims = make([]*Input, lenClaims)
|
||||
for i := 0; i < int(lenClaims); i++ {
|
||||
c.Claims[i] = &Input{}
|
||||
c.Claims[i].Decode(br)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEncodeDecodeClaim(t *testing.T) {
|
||||
|
||||
// test taken from mainnet: abf142faf539c340e42722b5b34b505cf4fd73185fed775784e37c2c5ef1b866
|
||||
rawtx := "020001af1b3a0f3729572893ce4e82f2113d18ec9a5e9d6fe02117eaa9e0c5a43770490000000001e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6048ae5801000000001123b6b74273562540479eea5cd0139f88ac7dd301414085f6d9edc24ab68c5d15c8e164de6702106c53bc15fa2c45b575bd3543c19132de61dd1922407be56affbcea73e5f8878811549340fd3c951e8593d51f3c8a962321028cf5e5a4d430db0202755c2cf1b3c99efcb4da4e41e182450dc5e1ddffb54bbfac"
|
||||
rawtxBytes, _ := hex.DecodeString(rawtx)
|
||||
|
||||
c := NewClaim(0)
|
||||
|
||||
r := bytes.NewReader(rawtxBytes)
|
||||
err := c.Decode(r)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
assert.Equal(t, types.Claim, c.Type)
|
||||
assert.Equal(t, 0, int(c.Version))
|
||||
assert.Equal(t, 1, int(len(c.Claims)))
|
||||
|
||||
claim := c.Claims[0]
|
||||
assert.Equal(t, "497037a4c5e0a9ea1721e06f9d5e9aec183d11f2824ece93285729370f3a1baf", claim.PrevHash.ReverseString())
|
||||
assert.Equal(t, uint16(0), claim.PrevIndex)
|
||||
assert.Equal(t, "abf142faf539c340e42722b5b34b505cf4fd73185fed775784e37c2c5ef1b866", c.Hash.ReverseString())
|
||||
|
||||
// Encode
|
||||
buf := new(bytes.Buffer)
|
||||
err = c.Encode(buf)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes()))
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
//Contract represents a contract transaction on the neo network
|
||||
type Contract struct {
|
||||
*Base
|
||||
}
|
||||
|
||||
//NewContract returns a contract transaction
|
||||
func NewContract(ver version.TX) *Contract {
|
||||
basicTrans := createBaseTransaction(types.Contract, ver)
|
||||
|
||||
contract := &Contract{
|
||||
basicTrans,
|
||||
}
|
||||
contract.encodeExclusive = contract.encodeExcl
|
||||
contract.decodeExclusive = contract.decodeExcl
|
||||
return contract
|
||||
}
|
||||
|
||||
func (c *Contract) encodeExcl(bw *util.BinWriter) {}
|
||||
|
||||
func (c *Contract) decodeExcl(br *util.BinReader) {}
|
|
@ -1,33 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
//Enrollment represents an Enrollment transaction on the neo network
|
||||
type Enrollment struct {
|
||||
*Base
|
||||
Key PublicKey
|
||||
}
|
||||
|
||||
//NewEnrollment returns an Enrollment transaction
|
||||
func NewEnrollment(ver version.TX) *Enrollment {
|
||||
basicTrans := createBaseTransaction(types.Enrollment, ver)
|
||||
|
||||
enrollment := &Enrollment{
|
||||
Base: basicTrans,
|
||||
}
|
||||
enrollment.encodeExclusive = enrollment.encodeExcl
|
||||
enrollment.decodeExclusive = enrollment.decodeExcl
|
||||
return enrollment
|
||||
}
|
||||
|
||||
func (e *Enrollment) encodeExcl(bw *util.BinWriter) {
|
||||
e.Key.Encode(bw)
|
||||
}
|
||||
|
||||
func (e *Enrollment) decodeExcl(br *util.BinReader) {
|
||||
e.Key.Decode(br)
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util/fixed8"
|
||||
)
|
||||
|
||||
//Invocation represents an invocation transaction on the neo network
|
||||
type Invocation struct {
|
||||
*Base
|
||||
Script []byte
|
||||
Gas fixed8.Fixed8
|
||||
}
|
||||
|
||||
//NewInvocation returns an invocation transaction
|
||||
func NewInvocation(ver version.TX) *Invocation {
|
||||
basicTrans := createBaseTransaction(types.Invocation, ver)
|
||||
|
||||
invocation := &Invocation{}
|
||||
invocation.Base = basicTrans
|
||||
invocation.encodeExclusive = invocation.encodeExcl
|
||||
invocation.decodeExclusive = invocation.decodeExcl
|
||||
return invocation
|
||||
}
|
||||
|
||||
func (c *Invocation) encodeExcl(bw *util.BinWriter) {
|
||||
bw.VarUint(uint64(len(c.Script)))
|
||||
bw.Write(c.Script)
|
||||
|
||||
switch c.Version {
|
||||
case 0:
|
||||
c.Gas = fixed8.Fixed8(0)
|
||||
case 1:
|
||||
bw.Write(&c.Gas)
|
||||
default:
|
||||
bw.Write(&c.Gas)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Invocation) decodeExcl(br *util.BinReader) {
|
||||
|
||||
lenScript := br.VarUint()
|
||||
c.Script = make([]byte, lenScript)
|
||||
br.Read(&c.Script)
|
||||
|
||||
switch c.Version {
|
||||
case 0:
|
||||
c.Gas = fixed8.Fixed8(0)
|
||||
case 1:
|
||||
br.Read(&c.Gas)
|
||||
default:
|
||||
br.Err = errors.New("invalid Version Number for Invocation Transaction")
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEncodeDecodeInvoc(t *testing.T) {
|
||||
// taken from mainnet b2a22cd9dd7636ae23e25576866cd1d9e2f3d85a85e80874441f085cd60006d1
|
||||
|
||||
rawtx := "d10151050034e23004141ad842821c7341d5a32b17d7177a1750d30014ca14628c9e5bc6a9346ca6bcdf050ceabdeb2bdc774953c1087472616e736665726703e1df72015bdef1a1b9567d4700635f23b1f406f100000000000000000220628c9e5bc6a9346ca6bcdf050ceabdeb2bdc7749f02f31363a30373a3032203a2030333366616431392d643638322d343035382d626437662d31356339333132343433653800000141403ced56c16f933e0a0a7d37470e114f6a4216ef9b834d61db67b74b9bd117370d10870857c0ee8adcf9956bc9fc92c5158de0c2db34ef459c17de042f20ad8fe92321027392870a5994b090d1750dda173a54df8dad324ed6d9ed25290d17c59059a112ac"
|
||||
rawtxBytes, _ := hex.DecodeString(rawtx)
|
||||
|
||||
i := NewInvocation(30)
|
||||
|
||||
r := bytes.NewReader(rawtxBytes)
|
||||
err := i.Decode(r)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
assert.Equal(t, types.Invocation, i.Type)
|
||||
|
||||
assert.Equal(t, 2, len(i.Attributes))
|
||||
|
||||
attr1 := i.Attributes[0]
|
||||
assert.Equal(t, Script, attr1.Usage)
|
||||
assert.Equal(t, "628c9e5bc6a9346ca6bcdf050ceabdeb2bdc7749", hex.EncodeToString(attr1.Data))
|
||||
|
||||
attr2 := i.Attributes[1]
|
||||
assert.Equal(t, Remark, attr2.Usage)
|
||||
assert.Equal(t, "31363a30373a3032203a2030333366616431392d643638322d343035382d626437662d313563393331323434336538", hex.EncodeToString(attr2.Data))
|
||||
|
||||
assert.Equal(t, "050034e23004141ad842821c7341d5a32b17d7177a1750d30014ca14628c9e5bc6a9346ca6bcdf050ceabdeb2bdc774953c1087472616e736665726703e1df72015bdef1a1b9567d4700635f23b1f406f1", hex.EncodeToString(i.Script))
|
||||
assert.Equal(t, "b2a22cd9dd7636ae23e25576866cd1d9e2f3d85a85e80874441f085cd60006d1", i.Hash.ReverseString())
|
||||
|
||||
// Encode
|
||||
buf := new(bytes.Buffer)
|
||||
err = i.Encode(buf)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, rawtxBytes, buf.Bytes())
|
||||
}
|
||||
|
||||
func TestEncodeDecodeInvocAttributes(t *testing.T) {
|
||||
// taken from mainnet cb0b5edc7e87b3b1bd9e029112fd3ce17c16d3de20c43ca1c0c26f3add578ecb
|
||||
|
||||
rawtx := "d1015308005b950f5e010000140000000000000000000000000000000000000000141a1e29d6232d2148e1e71e30249835ea41eb7a3d53c1087472616e7366657267fb1c540417067c270dee32f21023aa8b9b71abce000000000000000002201a1e29d6232d2148e1e71e30249835ea41eb7a3d8110f9f504da6334935a2db42b18296d88700000014140461370f6847c4abbdddff54a3e1337e453ecc8133c882ec5b9aabcf0f47dafd3432d47e449f4efc77447ef03519b7808c450a998cca3ecc10e6536ed9db862ba23210285264b6f349f0fe86e9bb3044fde8f705b016593cf88cd5e8a802b78c7d2c950ac"
|
||||
rawtxBytes, _ := hex.DecodeString(rawtx)
|
||||
|
||||
i := NewInvocation(30)
|
||||
|
||||
r := bytes.NewReader(rawtxBytes)
|
||||
err := i.Decode(r)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
assert.Equal(t, types.Invocation, i.Type)
|
||||
|
||||
assert.Equal(t, 1, int(i.Version))
|
||||
|
||||
assert.Equal(t, 2, len(i.Attributes))
|
||||
|
||||
assert.Equal(t, Script, i.Attributes[0].Usage)
|
||||
assert.Equal(t, "1a1e29d6232d2148e1e71e30249835ea41eb7a3d", hex.EncodeToString(i.Attributes[0].Data))
|
||||
assert.Equal(t, DescriptionURL, i.Attributes[1].Usage)
|
||||
assert.Equal(t, "f9f504da6334935a2db42b18296d8870", hex.EncodeToString(i.Attributes[1].Data))
|
||||
|
||||
assert.Equal(t, "08005b950f5e010000140000000000000000000000000000000000000000141a1e29d6232d2148e1e71e30249835ea41eb7a3d53c1087472616e7366657267fb1c540417067c270dee32f21023aa8b9b71abce", hex.EncodeToString(i.Script))
|
||||
assert.Equal(t, "cb0b5edc7e87b3b1bd9e029112fd3ce17c16d3de20c43ca1c0c26f3add578ecb", i.Hash.ReverseString())
|
||||
|
||||
// Encode
|
||||
buf := new(bytes.Buffer)
|
||||
err = i.Encode(buf)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, rawtxBytes, buf.Bytes())
|
||||
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
// Issue represents an issue transaction on the neo network
|
||||
type Issue struct {
|
||||
*Base
|
||||
}
|
||||
|
||||
//NewIssue returns an issue transaction
|
||||
func NewIssue(ver version.TX) *Issue {
|
||||
basicTrans := createBaseTransaction(types.Issue, ver)
|
||||
|
||||
Issue := &Issue{
|
||||
basicTrans,
|
||||
}
|
||||
Issue.encodeExclusive = Issue.encodeExcl
|
||||
Issue.decodeExclusive = Issue.decodeExcl
|
||||
return Issue
|
||||
}
|
||||
|
||||
func (c *Issue) encodeExcl(bw *util.BinWriter) {
|
||||
if c.Version > 1 {
|
||||
bw.Err = errors.New("Version Number Invalid, Issue cannot be more than 0")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Issue) decodeExcl(br *util.BinReader) {}
|
|
@ -1,8 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEncodeDecodeIssue(t *testing.T) {
|
||||
|
||||
// This is the same as Contract, as it has no special fields.
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
//Miner represents a miner transaction on the neo network
|
||||
type Miner struct {
|
||||
*Base
|
||||
Nonce uint32
|
||||
}
|
||||
|
||||
//NewMiner returns a miner transaction
|
||||
func NewMiner(ver version.TX) *Miner {
|
||||
basicTrans := createBaseTransaction(types.Miner, ver)
|
||||
|
||||
Miner := &Miner{}
|
||||
Miner.Base = basicTrans
|
||||
Miner.encodeExclusive = Miner.encodeExcl
|
||||
Miner.decodeExclusive = Miner.decodeExcl
|
||||
return Miner
|
||||
}
|
||||
|
||||
func (c *Miner) encodeExcl(bw *util.BinWriter) {
|
||||
bw.Write(c.Nonce)
|
||||
}
|
||||
|
||||
func (c *Miner) decodeExcl(br *util.BinReader) {
|
||||
br.Read(&c.Nonce)
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package transaction
|
||||
|
||||
// ParamType represent the Type of the contract parameter
|
||||
type ParamType uint8
|
||||
|
||||
// A list of supported smart contract parameter types.
|
||||
const (
|
||||
SignatureType ParamType = iota
|
||||
BoolType
|
||||
IntegerType
|
||||
Hash160Type
|
||||
Hash256Type
|
||||
ByteArrayType
|
||||
PublicKeyType
|
||||
StringType
|
||||
ArrayType
|
||||
)
|
|
@ -1,38 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
// PublicKey represents a public key on the neo network
|
||||
type PublicKey struct {
|
||||
Key []byte
|
||||
}
|
||||
|
||||
//Encode encodes a public key into a binary writer
|
||||
func (p *PublicKey) Encode(bw *util.BinWriter) {
|
||||
bw.Write(p.Key)
|
||||
}
|
||||
|
||||
// Decode decodes a bianry reader into a public key
|
||||
func (p *PublicKey) Decode(br *util.BinReader) {
|
||||
var prefix uint8
|
||||
br.Read(&prefix)
|
||||
|
||||
// Compressed public keys.
|
||||
if prefix == 0x02 || prefix == 0x03 {
|
||||
p.Key = make([]byte, 32)
|
||||
br.Read(p.Key)
|
||||
} else if prefix == 0x04 {
|
||||
p.Key = make([]byte, 65)
|
||||
br.Read(p.Key)
|
||||
} else if prefix == 0x00 {
|
||||
// do nothing, For infinity, the p.Key == 0x00, included in the prefix
|
||||
} else {
|
||||
br.Err = errors.New("Prefix not recognised for public key")
|
||||
return
|
||||
}
|
||||
p.Key = append([]byte{prefix}, p.Key...)
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
// Publish represents a publish transaction on the neo network
|
||||
type Publish struct {
|
||||
*Base
|
||||
Script []byte
|
||||
ParamList []ParamType
|
||||
ReturnType ParamType
|
||||
NeedStorage byte
|
||||
Name string
|
||||
CodeVersion string
|
||||
Author string
|
||||
Email string
|
||||
Description string
|
||||
}
|
||||
|
||||
//NewPublish returns a publish transaction
|
||||
func NewPublish(ver version.TX) *Publish {
|
||||
basicTrans := createBaseTransaction(types.Publish, ver)
|
||||
|
||||
Publish := &Publish{}
|
||||
Publish.Base = basicTrans
|
||||
Publish.encodeExclusive = Publish.encodeExcl
|
||||
Publish.decodeExclusive = Publish.decodeExcl
|
||||
return Publish
|
||||
}
|
||||
|
||||
func (p *Publish) encodeExcl(bw *util.BinWriter) {
|
||||
bw.VarBytes(p.Script)
|
||||
bw.VarUint(uint64(len(p.ParamList)))
|
||||
for _, param := range p.ParamList {
|
||||
bw.Write(param)
|
||||
}
|
||||
|
||||
bw.Write(p.ReturnType)
|
||||
switch p.Version {
|
||||
case 0:
|
||||
p.NeedStorage = byte(0)
|
||||
case 1:
|
||||
bw.Write(p.NeedStorage)
|
||||
default:
|
||||
bw.Err = errors.New("Version Number unknown for Publish Transaction")
|
||||
}
|
||||
|
||||
bw.VarString(p.Name)
|
||||
bw.VarString(p.CodeVersion)
|
||||
bw.VarString(p.Author)
|
||||
bw.VarString(p.Email)
|
||||
bw.VarString(p.Description)
|
||||
|
||||
}
|
||||
|
||||
func (p *Publish) decodeExcl(br *util.BinReader) {
|
||||
p.Script = br.VarBytes()
|
||||
|
||||
lenParams := br.VarUint()
|
||||
p.ParamList = make([]ParamType, lenParams)
|
||||
for i := 0; i < int(lenParams); i++ {
|
||||
var ptype uint8
|
||||
br.Read(&ptype)
|
||||
p.ParamList[i] = ParamType(ptype)
|
||||
}
|
||||
|
||||
var rtype uint8
|
||||
br.Read(&rtype)
|
||||
p.ReturnType = ParamType(rtype)
|
||||
|
||||
switch p.Version {
|
||||
case 0:
|
||||
p.NeedStorage = byte(0)
|
||||
case 1:
|
||||
br.Read(&p.NeedStorage)
|
||||
default:
|
||||
br.Err = errors.New("Version Number unknown for Publish Transaction")
|
||||
}
|
||||
|
||||
p.Name = br.VarString()
|
||||
p.CodeVersion = br.VarString()
|
||||
p.Author = br.VarString()
|
||||
p.Email = br.VarString()
|
||||
p.Description = br.VarString()
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEncodeDecodePublish(t *testing.T) {
|
||||
///transaction taken from neo-python; can be found on testnet 5467a1fc8723ceffa8e5ee59399b02eea1df6fbaa53768c6704b90b960d223fa
|
||||
// taken from neo-python;
|
||||
rawtx := "d000fd3f01746b4c04000000004c04000000004c040000000061681e416e745368617265732e426c6f636b636861696e2e476574486569676874681d416e745368617265732e426c6f636b636861696e2e476574426c6f636b744c0400000000948c6c766b947275744c0402000000936c766b9479744c0400000000948c6c766b9479681d416e745368617265732e4865616465722e47657454696d657374616d70a0744c0401000000948c6c766b947275744c0401000000948c6c766b9479641b004c0400000000744c0402000000948c6c766b947275623000744c0401000000936c766b9479744c0400000000936c766b9479ac744c0402000000948c6c766b947275620300744c0402000000948c6c766b947961748c6c766b946d748c6c766b946d748c6c766b946d746c768c6b946d746c768c6b946d746c768c6b946d6c75660302050001044c6f636b0c312e302d70726576696577310a4572696b205a68616e67126572696b40616e747368617265732e6f7267234c6f636b20796f75722061737365747320756e74696c20612074696d657374616d702e00014e23ac4c4851f93407d4c59e1673171f39859db9e7cac72540cd3cc1ae0cca87000001e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6000ebcaaa0d00000067f97110a66136d38badc7b9f88eab013027ce49014140c298da9f06d5687a0bb87ea3bba188b7dcc91b9667ea5cb71f6fdefe388f42611df29be9b2d6288655b9f2188f46796886afc3b37d8b817599365d9e161ecfb62321034b44ed9c8a88fb2497b6b57206cc08edd42c5614bd1fee790e5b795dee0f4e11ac"
|
||||
rawtxBytes, _ := hex.DecodeString(rawtx)
|
||||
|
||||
publ := NewPublish(30)
|
||||
|
||||
r := bytes.NewReader(rawtxBytes)
|
||||
err := publ.Decode(r)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
assert.Equal(t, types.Publish, publ.Type)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err = publ.Encode(buf)
|
||||
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes()))
|
||||
assert.Equal(t, "5467a1fc8723ceffa8e5ee59399b02eea1df6fbaa53768c6704b90b960d223fa", publ.Hash.ReverseString())
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util/fixed8"
|
||||
)
|
||||
|
||||
// Register represents a register transaction on the neo network
|
||||
type Register struct {
|
||||
*Base
|
||||
// The type of the asset being registered.
|
||||
AssetType AssetType
|
||||
|
||||
// Name of the asset being registered.
|
||||
Name string
|
||||
|
||||
// Amount registered
|
||||
// Unlimited mode -0.00000001
|
||||
Amount fixed8.Fixed8
|
||||
|
||||
// Decimals
|
||||
Precision uint8
|
||||
|
||||
// Public key of the owner
|
||||
Owner PublicKey
|
||||
|
||||
Admin util.Uint160
|
||||
}
|
||||
|
||||
//NewRegister returns a register transaction
|
||||
func NewRegister(ver version.TX) *Register {
|
||||
basicTrans := createBaseTransaction(types.Register, ver)
|
||||
Register := &Register{}
|
||||
Register.Base = basicTrans
|
||||
Register.encodeExclusive = Register.encodeExcl
|
||||
Register.decodeExclusive = Register.decodeExcl
|
||||
return Register
|
||||
}
|
||||
|
||||
func (r *Register) encodeExcl(bw *util.BinWriter) {
|
||||
bw.Write(r.AssetType)
|
||||
bw.VarString(r.Name)
|
||||
bw.Write(r.Amount)
|
||||
bw.Write(r.Precision)
|
||||
r.Owner.Encode(bw)
|
||||
bw.Write(r.Admin)
|
||||
}
|
||||
|
||||
func (r *Register) decodeExcl(br *util.BinReader) {
|
||||
br.Read(&r.AssetType)
|
||||
r.Name = br.VarString()
|
||||
br.Read(&r.Amount)
|
||||
br.Read(&r.Precision)
|
||||
r.Owner.Decode(br)
|
||||
br.Read(&r.Admin)
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEncodeDecodeRegister(t *testing.T) {
|
||||
// transaction taken from neo-python; can be found on testnet 0c092117b4ba47b81001712425e6e7f760a637695eaf23741ba335925b195ecd
|
||||
|
||||
rawtx := "400060245b7b226c616e67223a227a682d434e222c226e616d65223a2254657374436f696e227d5dffffffffffffffff08034b44ed9c8a88fb2497b6b57206cc08edd42c5614bd1fee790e5b795dee0f4e1167f97110a66136d38badc7b9f88eab013027ce4900014423a26aeca49cdeeb9522c720e1ae3a93bbe27d53662839b16a438305c20906010001e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c60001e1a210b00000067f97110a66136d38badc7b9f88eab013027ce490141405d8223ec807e3416a220a75ef9805dfa2e36bd4f6dcc7372373aa45f15c7fadfc96a8642e52acf56c2c66d549be4ba820484873d5cada00b9c1ce9674fbf96382321034b44ed9c8a88fb2497b6b57206cc08edd42c5614bd1fee790e5b795dee0f4e11ac"
|
||||
rawtxBytes, _ := hex.DecodeString(rawtx)
|
||||
|
||||
reg := NewRegister(0)
|
||||
|
||||
r := bytes.NewReader(rawtxBytes)
|
||||
err := reg.Decode(r)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
assert.Equal(t, types.Register, reg.Type)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err = reg.Encode(buf)
|
||||
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes()))
|
||||
assert.Equal(t, "0c092117b4ba47b81001712425e6e7f760a637695eaf23741ba335925b195ecd", reg.Hash.ReverseString())
|
||||
}
|
||||
func TestEncodeDecodeGenesisRegister(t *testing.T) {
|
||||
|
||||
// genesis transaction taken from mainnet; can be found on mainnet(Block 0) : c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b
|
||||
|
||||
rawtx := "400000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000"
|
||||
rawtxBytes, _ := hex.DecodeString(rawtx)
|
||||
|
||||
reg := NewRegister(0)
|
||||
|
||||
r := bytes.NewReader(rawtxBytes)
|
||||
err := reg.Decode(r)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
assert.Equal(t, types.Register, reg.Type)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err = reg.Encode(buf)
|
||||
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes()))
|
||||
assert.Equal(t, "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", reg.Hash.ReverseString())
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/version"
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
//StateTX represents a state transaction on the neo network
|
||||
// XXX: TX postfix here as `state` is ambiguous. We can remove it for consistency
|
||||
type StateTX struct {
|
||||
*Base
|
||||
Descriptors []*StateDescriptor
|
||||
}
|
||||
|
||||
//NewStateTX returns a state transaction
|
||||
func NewStateTX(ver version.TX) *StateTX {
|
||||
basicTrans := createBaseTransaction(types.State, ver)
|
||||
|
||||
StateTX := &StateTX{}
|
||||
StateTX.Base = basicTrans
|
||||
StateTX.encodeExclusive = StateTX.encodeExcl
|
||||
StateTX.decodeExclusive = StateTX.decodeExcl
|
||||
return StateTX
|
||||
}
|
||||
|
||||
func (s *StateTX) encodeExcl(bw *util.BinWriter) {
|
||||
|
||||
bw.VarUint(uint64(len(s.Descriptors)))
|
||||
for _, desc := range s.Descriptors {
|
||||
desc.Encode(bw)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StateTX) decodeExcl(br *util.BinReader) {
|
||||
lenDesc := br.VarUint()
|
||||
|
||||
s.Descriptors = make([]*StateDescriptor, lenDesc)
|
||||
for i := 0; i < int(lenDesc); i++ {
|
||||
s.Descriptors[i] = &StateDescriptor{}
|
||||
s.Descriptors[i].Decode(br)
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
// DescStateType represents the type of StateDescriptor.
|
||||
type DescStateType uint8
|
||||
|
||||
// Valid DescStateType constants.
|
||||
const (
|
||||
Account DescStateType = 0x40
|
||||
Validator DescStateType = 0x48
|
||||
)
|
||||
|
||||
// StateDescriptor represents a state descriptor on the neo network
|
||||
// used in a state transaction
|
||||
type StateDescriptor struct {
|
||||
Type DescStateType
|
||||
Key []byte
|
||||
Value []byte
|
||||
Field string
|
||||
}
|
||||
|
||||
// Decode decodes a binary reader into a state descriptor
|
||||
func (s *StateDescriptor) Decode(br *util.BinReader) {
|
||||
br.Read(&s.Type)
|
||||
|
||||
keyLen := br.VarUint()
|
||||
s.Key = make([]byte, keyLen)
|
||||
br.Read(s.Key)
|
||||
|
||||
valLen := br.VarUint()
|
||||
s.Value = make([]byte, valLen)
|
||||
br.Read(s.Value)
|
||||
|
||||
fieldLen := br.VarUint()
|
||||
field := make([]byte, fieldLen)
|
||||
br.Read(field)
|
||||
|
||||
s.Field = string(field)
|
||||
}
|
||||
|
||||
//Encode encodes a state descriptor into a binary writer
|
||||
func (s *StateDescriptor) Encode(bw *util.BinWriter) {
|
||||
bw.Write(s.Type)
|
||||
|
||||
bw.VarUint(uint64(len(s.Key)))
|
||||
bw.Write(s.Key)
|
||||
|
||||
bw.VarUint(uint64(len(s.Value)))
|
||||
bw.Write(s.Value)
|
||||
|
||||
bw.VarString(s.Field)
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
// TX is the type of a transaction.
|
||||
type TX uint8
|
||||
|
||||
// List of transaction types
|
||||
const (
|
||||
Miner TX = 0x00
|
||||
Issue TX = 0x01
|
||||
Claim TX = 0x02
|
||||
Enrollment TX = 0x20
|
||||
Voting TX = 0x24
|
||||
Register TX = 0x40
|
||||
Contract TX = 0x80
|
||||
State TX = 0x90
|
||||
Agency TX = 0xb0
|
||||
Publish TX = 0xd0
|
||||
Invocation TX = 0xd1
|
||||
)
|
||||
|
||||
// Encode encodes a tx type into the binary writer
|
||||
func (t *TX) Encode(bw *util.BinWriter) {
|
||||
bw.Write(t)
|
||||
}
|
||||
|
||||
// Decode decodes a binary reader into a tx type
|
||||
func (t *TX) Decode(br *util.BinReader) {
|
||||
br.Read(t)
|
||||
}
|
||||
|
||||
// String implements the stringer interface.
|
||||
func (t TX) String() string {
|
||||
switch t {
|
||||
case Miner:
|
||||
return "MinerTransaction"
|
||||
case Issue:
|
||||
return "IssueTransaction"
|
||||
case Claim:
|
||||
return "ClaimTransaction"
|
||||
case Enrollment:
|
||||
return "EnrollmentTransaction"
|
||||
case Voting:
|
||||
return "VotingTransaction"
|
||||
case Register:
|
||||
return "RegisterTransaction"
|
||||
case Contract:
|
||||
return "ContractTransaction"
|
||||
case State:
|
||||
return "StateTransaction"
|
||||
case Agency:
|
||||
return "AgencyTransaction"
|
||||
case Publish:
|
||||
return "PublishTransaction"
|
||||
case Invocation:
|
||||
return "InvocationTransaction"
|
||||
default:
|
||||
return "UnkownTransaction"
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction/types"
|
||||
)
|
||||
|
||||
// FromReader returns a transaction from a bufio.Reader
|
||||
func FromReader(reader *bufio.Reader) (Transactioner, error) {
|
||||
|
||||
t, err := reader.Peek(1)
|
||||
|
||||
typ := types.TX(t[0])
|
||||
var trans Transactioner
|
||||
|
||||
switch typ {
|
||||
case types.Miner:
|
||||
miner := NewMiner(0)
|
||||
err = miner.Decode(reader)
|
||||
trans = miner
|
||||
case types.Contract:
|
||||
contract := NewContract(0)
|
||||
err = contract.Decode(reader)
|
||||
trans = contract
|
||||
case types.Invocation:
|
||||
invoc := NewInvocation(0)
|
||||
err = invoc.Decode(reader)
|
||||
trans = invoc
|
||||
case types.Claim:
|
||||
claim := NewClaim(0)
|
||||
err = claim.Decode(reader)
|
||||
trans = claim
|
||||
case types.Register:
|
||||
reg := NewRegister(0)
|
||||
err = reg.Decode(reader)
|
||||
trans = reg
|
||||
case types.Issue:
|
||||
iss := NewIssue(0)
|
||||
err = iss.Decode(reader)
|
||||
trans = iss
|
||||
case types.Publish:
|
||||
pub := NewPublish(0)
|
||||
err = pub.Decode(reader)
|
||||
trans = pub
|
||||
case types.State:
|
||||
state := NewStateTX(0)
|
||||
err = state.Decode(reader)
|
||||
trans = state
|
||||
case types.Enrollment:
|
||||
enr := NewEnrollment(0)
|
||||
err = enr.Decode(reader)
|
||||
trans = enr
|
||||
case types.Agency:
|
||||
err = errors.New("unsupported transaction type: Agency")
|
||||
default:
|
||||
err = errors.New("unsupported transaction with byte type " + hex.EncodeToString([]byte{t[0]}))
|
||||
}
|
||||
return trans, err
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/wire/util"
|
||||
)
|
||||
|
||||
// TX represents a tx version
|
||||
type TX uint8
|
||||
|
||||
// List of latest tx version
|
||||
const (
|
||||
Contract TX = 0
|
||||
Invocation TX = 1
|
||||
)
|
||||
|
||||
// Encode encodes the tx version into the binary writer
|
||||
func (v *TX) Encode(bw *util.BinWriter) {
|
||||
bw.Write(v)
|
||||
}
|
||||
|
||||
// Decode decodes the binary reader into a tx type
|
||||
func (v *TX) Decode(br *util.BinReader) {
|
||||
br.Read(v)
|
||||
}
|
Loading…
Reference in a new issue