Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented rpc server method GetRawTransaction #135

Merged
merged 25 commits into from
Feb 20, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
41e27d7
Added utility function GetVarSize
dauTT Feb 10, 2019
79f41f9
1) Added Size method: this implied that Fixed8 implements now the ser…
dauTT Feb 10, 2019
a837151
Implemented Size or MarshalJSON method.
dauTT Feb 10, 2019
c280890
Added fee calculation
dauTT Feb 10, 2019
30d0a4a
Implemented rcp server method GetRawTransaction
dauTT Feb 10, 2019
6540cf8
Updated Tests
dauTT Feb 10, 2019
ba3393e
Fixed:
dauTT Feb 12, 2019
36b69e4
Simplified Size calculation
dauTT Feb 12, 2019
df11e05
1) Removed global variable blockchainDefault, configDefault
dauTT Feb 13, 2019
42590dc
Simplified GetVarSize Method
dauTT Feb 13, 2019
38528c5
Merge branch 'master' into dauTT/patch-5
dauTT Feb 14, 2019
9b91af1
Replaced ValueAtAndType with ValueWithType
dauTT Feb 14, 2019
04a25fe
Cosmetic changes + Added test case getrawtransaction_7
dauTT Feb 14, 2019
5bff6c4
Clean up Print statement
dauTT Feb 14, 2019
974e986
Filled up keys
dauTT Feb 17, 2019
087ea47
Aligned verbose logic with the C#-neo implementation
dauTT Feb 17, 2019
4b4822a
Implemented @Kim requests
dauTT Feb 17, 2019
94ac1d3
Small fixes
dauTT Feb 17, 2019
5b9f828
Fixed verbose logic
dauTT Feb 18, 2019
da3f83f
Replaced assert.NoError with require.NoError
dauTT Feb 18, 2019
a9d07e8
Merge branch 'master' into dauTT/patch-5
dauTT Feb 19, 2019
a8328ff
Merge branch 'master' into dauTT/patch-5
dauTT Feb 19, 2019
18b6b35
Fixed tests by adding context.Background() as argument
dauTT Feb 19, 2019
b576289
Merge branch 'master' into dauTT/patch-5
dauTT Feb 20, 2019
61b8e96
Fixed tests
dauTT Feb 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"os"
"time"

"github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/go-yaml/yaml"
"github.com/pkg/errors"
)
Expand All @@ -27,6 +29,9 @@ var (
// BuildTime the time and date the current version of the node built,
// set at build time.
BuildTime string

// ConfigDefault is the Config which has been initialized in the Load method.
ConfigDefault *Config
)

type (
Expand All @@ -49,10 +54,10 @@ type (

// SystemFee fees related to system.
SystemFee struct {
EnrollmentTransaction int64 `yaml:"EnrollmentTransaction"`
IssueTransaction int64 `yaml:"IssueTransaction"`
PublishTransaction int64 `yaml:"PublishTransaction"`
RegisterTransaction int64 `yaml:"RegisterTransaction"`
EnrollmentTransaction int `yaml:"EnrollmentTransaction"`
IssueTransaction int `yaml:"IssueTransaction"`
PublishTransaction int `yaml:"PublishTransaction"`
RegisterTransaction int `yaml:"RegisterTransaction"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it must be int64

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or.. mb float64

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the C# implementation is int64

public Fixed8(long data)
        {
            this.value = data;
        }

Why do you suggest float64?

Shall I change everything so that the NewFixed8 method accept int64?

// NewFixed8 return a new Fixed8 type multiplied by decimals.
func NewFixed8(val int64) Fixed8 {
	return Fixed8(decimals * val)
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dauTT yep, long / int64 for new.. but...

public Fixed8(long data)
        {
            this.value = data;
        }

and

        public static Fixed8 FromDecimal(decimal value)
        {
            value *= D;
            if (value < long.MinValue || value > long.MaxValue)
                throw new OverflowException();
            return new Fixed8
            {
                value = (long)value
            };
        }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private const long D = 100_000_000;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, I think I understood what you mean.

}

// ApplicationConfiguration config specific to the node.
Expand Down Expand Up @@ -116,5 +121,26 @@ func Load(path string, netMode NetMode) (Config, error) {
return Config{}, errors.Wrap(err, "Problem unmarshaling config json data")
}

setConfigDefault(&config)

return config, nil
}

func setConfigDefault(cfg *Config) {
ConfigDefault = cfg
}

func (s SystemFee) TryGetValue(txType transaction.TXType) util.Fixed8 {
switch txType {
case transaction.EnrollmentType:
return util.NewFixed8(s.EnrollmentTransaction)
case transaction.IssueType:
return util.NewFixed8(s.IssueTransaction)
case transaction.PublishType:
return util.NewFixed8(s.PublishTransaction)
case transaction.RegisterType:
return util.NewFixed8(s.RegisterTransaction)
default:
return util.NewFixed8(0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we must fix NewFixed8 method:

// NewFixed8 return a new Fixed8 type multiplied by decimals.
func NewFixed8(val int64) Fixed8 {
	return Fixed8(decimals * val)
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or mb to:

// NewFixed8 return a new Fixed8 type multiplied by decimals.
func NewFixed8(val float64) Fixed8 {
	return Fixed8(int64(decimals * val))
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see there

}
}
16 changes: 12 additions & 4 deletions pkg/core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ var (
genAmount = []int{8, 7, 6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
decrementInterval = 2000000
persistInterval = 1 * time.Second

BlockchainDefault *Blockchain
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it can't be exported

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean it can't be exported? I Do need to register a blockchain as a default one in order to use it in the References method in the fee.go file.

func References(t *transaction.Transaction) map[util.Uint256]*transaction.Output {
	references := make(map[util.Uint256]*transaction.Output)

 	for prevHash, inputs := range t.GroupInputsByPrevHash() {
		if BlockchainDefault == nil {
			panic("no default blockchain available! please register one.")
		} else if tx, _, err := BlockchainDefault.GetTransaction(prevHash); err != nil {
			tx = nil
		} else if tx != nil {
			for _, in := range inputs {
				references[in.PrevHash] = tx.Outputs[in.PrevIndex]
			}
		} else {
			references = nil
		}
	}
	return references
}

At least within the core package, I do not have any problem to use it BlockchainDefault.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data race in runtime...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a bad practice, to set globalVariable..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the link!

)

// Blockchain represents the blockchain.
Expand Down Expand Up @@ -75,10 +77,11 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration) (*Blockcha
return nil, err
}

RegisterBlockchain(bc)
return bc, nil
}

// GetBlockchainLevelDB returns blockchain based on configuration
// NewBlockchainLevelDB returns LevelDB blockchain based on configuration
func NewBlockchainLevelDB(cfg config.Config) (*Blockchain, error) {
store, err := storage.NewLevelDBStore(
cfg.ApplicationConfiguration.DataDirectoryPath,
Expand Down Expand Up @@ -148,7 +151,7 @@ func (bc *Blockchain) init() error {
headers := make([]*Header, 0)

for hash != targetHash {
header, err := bc.getHeader(hash)
header, err := bc.GetHeader(hash)
if err != nil {
return fmt.Errorf("could not get header %s: %s", hash, err)
}
Expand Down Expand Up @@ -179,6 +182,11 @@ func (bc *Blockchain) run() {
}
}

// RegisterBlockchain registers a blockchain
func RegisterBlockchain(b *Blockchain) {
BlockchainDefault = b
}

// AddBlock processes the given block and will add it to the cache so it
// can be persisted.
func (bc *Blockchain) AddBlock(block *Block) error {
Expand Down Expand Up @@ -483,7 +491,7 @@ func (bc *Blockchain) GetBlock(hash util.Uint256) (*Block, error) {
return block, nil
}

func (bc *Blockchain) getHeader(hash util.Uint256) (*Header, error) {
func (bc *Blockchain) GetHeader(hash util.Uint256) (*Header, error) {
b, err := bc.Get(storage.AppendPrefix(storage.DataBlock, hash.BytesReverse()))
if err != nil {
return nil, err
Expand All @@ -504,7 +512,7 @@ func (bc *Blockchain) HasTransaction(hash util.Uint256) bool {
// HasBlock return true if the blockchain contains the given
// block hash.
func (bc *Blockchain) HasBlock(hash util.Uint256) bool {
if header, err := bc.getHeader(hash); err == nil {
if header, err := bc.GetHeader(hash); err == nil {
return header.Index <= bc.BlockHeight()
}
return false
Expand Down
4 changes: 2 additions & 2 deletions pkg/core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ func TestGetHeader(t *testing.T) {
assert.Nil(t, err)

hash := block.Hash()
header, err := bc.getHeader(hash)
header, err := bc.GetHeader(hash)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

require.NoError(t, err)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

t.Fatal(err)
}
assert.Equal(t, block.Header(), header)

block = newBlock(2)
hash = block.Hash()
_, err = bc.getHeader(block.Hash())
_, err = bc.GetHeader(block.Hash())
assert.NotNil(t, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace with assert.Error(t, err)

}

Expand Down
3 changes: 3 additions & 0 deletions pkg/core/blockchainer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package core

import (
"github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/util"
)

Expand All @@ -13,10 +14,12 @@ type Blockchainer interface {
HeaderHeight() uint32
GetBlock(hash util.Uint256) (*Block, error)
GetHeaderHash(int) util.Uint256
GetHeader(hash util.Uint256) (*Header, error)
CurrentHeaderHash() util.Uint256
CurrentBlockHash() util.Uint256
HasBlock(util.Uint256) bool
HasTransaction(util.Uint256) bool
GetAssetState(util.Uint256) *AssetState
GetAccountState(util.Uint160) *AccountState
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
}
60 changes: 60 additions & 0 deletions pkg/core/fee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package core

import (
"github.com/CityOfZion/neo-go/config"
"github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/util"
)

// References returns a map with input prevHash as key (util.Uint256)
// and transaction output as value from a transaction t.
// @TODO: unfortunately we couldn't attach this method to the Transaction struct in the
// transaction package because of a import cycle problem. Perhaps we should think to re-design
// the code base to avoid this situation.
func References(t *transaction.Transaction) map[util.Uint256]*transaction.Output {
references := make(map[util.Uint256]*transaction.Output)

for prevHash, inputs := range t.GroupInputsByPrevHash() {
if BlockchainDefault == nil {
panic("no default blockchain available! please register one.")
} else if tx, _, err := BlockchainDefault.GetTransaction(prevHash); err != nil {
tx = nil
} else if tx != nil {
for _, in := range inputs {
references[in.PrevHash] = tx.Outputs[in.PrevIndex]
}
} else {
references = nil
}
}
return references
}

// FeePerByte returns network fee divided by the size of the transaction
func FeePerByte(t *transaction.Transaction) util.Fixed8 {
return NetworkFee(t).Div(t.Size())
}

// NetworkFee returns network fee
func NetworkFee(t *transaction.Transaction) util.Fixed8 {
inputAmount := util.NewFixed8(0)
for _, txOutput := range References(t) {
if txOutput.AssetID == utilityTokenTX().Hash() {
inputAmount.Add(txOutput.Amount)
}
}

outputAmount := util.NewFixed8(0)
for _, txOutput := range t.Outputs {
if txOutput.AssetID == utilityTokenTX().Hash() {
outputAmount.Add(txOutput.Amount)
}
}

return inputAmount.Sub(outputAmount).Sub(SystemFee(t))
}

// SystemFee returns system fee
func SystemFee(t *transaction.Transaction) util.Fixed8 {
return config.ConfigDefault.ProtocolConfiguration.SystemFee.TryGetValue(t.Type)
}
55 changes: 55 additions & 0 deletions pkg/core/fee_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package core

import (
"fmt"
"testing"

"github.com/CityOfZion/neo-go/config"
"github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert"
)

func TestSize(t *testing.T) {
txID := "f999c36145a41306c846ea80290416143e8e856559818065be3f4e143c60e43a"
tx := getTestTransaction(txID, t)
fmt.Println(tx.Bytes())
assert.Equal(t, 283, tx.Size())
assert.Equal(t, 22, util.GetVarSize(tx.Attributes))
assert.Equal(t, 35, util.GetVarSize(tx.Inputs))
assert.Equal(t, 121, util.GetVarSize(tx.Outputs))
assert.Equal(t, 103, util.GetVarSize(tx.Scripts))
}

func getTestBlockchain(t *testing.T) *Blockchain {
net := config.ModeUnitTestNet
configPath := "../../config"
cfg, err := config.Load(configPath, net)
if err != nil {
t.Fatal("could not create levelDB chain", err)
}

// adjust datadirectory to point to the correct folder
cfg.ApplicationConfiguration.DataDirectoryPath = "../rpc/chains/unit_testnet"
chain, err := NewBlockchainLevelDB(cfg)
if err != nil {
t.Fatal("could not create levelDB chain", err)
}

return chain
}

func getTestTransaction(txID string, t *testing.T) *transaction.Transaction {
chain := getTestBlockchain(t)

txHash, err := util.Uint256DecodeString(txID)
if err != nil {
t.Fatalf("could not decode string %s to Uint256: err =%s", txID, err)
}

tx, _, err := chain.GetTransaction(txHash)
if err != nil {
t.Fatalf("Could not get transaction with hash=%s: err=%s", txHash, err)
}
return tx
}
54 changes: 54 additions & 0 deletions pkg/core/transaction/attr_usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,57 @@ const (
Remark14 AttrUsage = 0xfe
Remark15 AttrUsage = 0xff
)

// String implements the stringer interface.
func (attr AttrUsage) String() string {
attrLookup := map[AttrUsage]string{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mb we can move that to global?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

ContractHash: "ContractHash",
ECDH02: "ECDH02",
ECDH03: "ECDH03",
Script: "Script",
Vote: "Vote",
CertURL: "CertURL",
DescriptionURL: "DescriptionURL",
Description: "Description",

Hash1: "Hash1",
Hash2: "Hash2",
Hash3: "Hash3",
Hash4: "Hash4",
Hash5: "Hash5",
Hash6: "Hash6",
Hash7: "Hash7",
Hash8: "Hash8",
Hash9: "Hash9",
Hash10: "Hash10",
Hash11: "Hash11",
Hash12: "Hash12",
Hash13: "Hash13",
Hash14: "Hash14",
Hash15: "Hash15",

Remark: "Remark",
Remark1: "Remark1",
Remark2: "Remark2",
Remark3: "Remark3",
Remark4: "Remark4",
Remark5: "Remark5",
Remark6: "Remark6",
Remark7: "Remark7",
Remark8: "Remark8",
Remark9: "Remark9",
Remark10: "Remark10",
Remark11: "Remark11",
Remark12: "Remark12",
Remark13: "Remark13",
Remark14: "Remark14",
Remark15: "Remark15",
}

v, ok := attrLookup[attr]
if !ok {
return "Unkown Attribute"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if v, ok := attrLookup[attr]; ok {
  return v
}
return "Unkown Attribute"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


return v
}
33 changes: 33 additions & 0 deletions pkg/core/transaction/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package transaction

import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"unsafe"

"github.com/CityOfZion/neo-go/pkg/util"
)
Expand Down Expand Up @@ -77,3 +80,33 @@ func (attr *Attribute) EncodeBinary(w io.Writer) error {
}
return fmt.Errorf("failed encoding TX attribute usage: 0x%2x", attr.Usage)
}

// Size returns the size in number bytes of the Attribute
func (attr *Attribute) Size() int {
var b byte
if attr.Usage == ContractHash || attr.Usage == ECDH02 || attr.Usage == ECDH03 || attr.Usage == Vote || (attr.Usage >= Hash1 && attr.Usage <= Hash15) {
return int(unsafe.Sizeof(attr.Usage)) + 32
} else if attr.Usage == Script {
return int(unsafe.Sizeof(attr.Usage)) + 20
} else if attr.Usage == DescriptionURL {
return int(unsafe.Sizeof(attr.Usage)) + int(unsafe.Sizeof(b)) + len(attr.Data)
} else {
return int(unsafe.Sizeof(attr.Usage)) + util.GetVarSize(attr.Data)
}
}

// MarshalJSON implements the json Marschaller interface
func (attr *Attribute) MarshalJSON() ([]byte, error) {
j, err := json.Marshal(
struct {
Usage string `json:"usage"`
Data string `json:"data"`
}{
attr.Usage.String(),
hex.EncodeToString(attr.Data),
})
Copy link
Contributor

@im-kulikov im-kulikov Feb 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mb simplify that:

	return json.Marshal(map[string]string{
		"usage": attr.Usage.String(),
		"data": hex.EncodeToString(attr.Data),
	})

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think that we really need a structure for that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if err != nil {
return nil, err
}
return j, nil
}
Loading