Skip to content

55 genesis txs #74

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

Merged
merged 19 commits into from
Jul 18, 2019
Merged
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion common/chaintype/mainchain.go
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ func (*MainChain) GetTablePrefix() string {

// GetChainSmithingDelayTime return the value of chain smithing delay in second
func (*MainChain) GetChainSmithingDelayTime() int64 {
return 6
return 60
}

// GetName return the name of the chain : used in parsing chaintype across node
44 changes: 13 additions & 31 deletions common/crypto/signature.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,31 @@
package crypto

import (
"github.com/zoobc/zoobc-core/common/model"
"github.com/zoobc/zoobc-core/common/query"
"github.com/zoobc/zoobc-core/common/util"
"golang.org/x/crypto/ed25519"
)

type (
SignatureInterface interface {
Sign(payload, accountID []byte, seed string) []byte
Sign(payload []byte, accountType uint32, accountAddress, seed string) []byte
SignBlock(payload []byte, nodeSeed string) []byte
VerifySignature(payload, signature, accountID []byte) bool
VerifySignature(payload, signature []byte, accountType uint32, accountAddress string) bool
}

// Signature object handle signing and verifying different signature
Signature struct {
Executor query.ExecutorInterface
}
)

// NewSignature create new instance of signature object
func NewSignature(executor query.ExecutorInterface) *Signature {
return &Signature{
Executor: executor,
}
func NewSignature() *Signature {
return &Signature{}
}

// Sign accept account ID and payload to be signed then return the signature byte based on the
// signature method associated with account.Type
func (sig *Signature) Sign(payload, accountID []byte, seed string) []byte {

accountQuery := query.NewAccountQuery()
getQuery, condition := accountQuery.GetAccountByID(accountID)
accountRows, _ := sig.Executor.ExecuteSelect(getQuery, condition...)
var accounts []*model.Account
account := accountQuery.BuildModel(accounts, accountRows)
if len(account) == 0 {
return nil
}
switch account[0].AccountType {
func (sig *Signature) Sign(payload []byte, accountType uint32, accountAddress, seed string) []byte {
switch accountType {
case 0: // zoobc
accountPrivateKey := ed25519GetPrivateKeyFromSeed(seed)
signature := ed25519.Sign(accountPrivateKey, payload)
@@ -58,21 +45,16 @@ func (*Signature) SignBlock(payload []byte, nodeSeed string) []byte {

// VerifySignature accept payload (before without signature), signature and the account id
// then verify the signature + public key against the payload based on the
func (*Signature) VerifySignature(payload, signature, accountID []byte) bool {
// todo: Fetch account from accountID
account := &model.Account{
ID: []byte{4, 38, 68, 24, 230, 247, 88, 220, 119, 124, 51, 149, 127, 214, 82, 224, 72, 239, 56, 139,
255, 81, 229, 184, 77, 80, 80, 39, 254, 173, 28, 169},
AccountType: 0,
Address: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
}
func (*Signature) VerifySignature(payload, signature []byte, accountType uint32, accountAddress string) bool {

switch account.AccountType {
switch accountType {
case 0: // zoobc
result := ed25519.Verify(accountID, payload, signature)
accountPublicKey, _ := util.GetPublicKeyFromAddress(accountAddress)
result := ed25519.Verify(accountPublicKey, payload, signature)
return result
default:
result := ed25519.Verify(accountID, payload, signature)
accountPublicKey, _ := util.GetPublicKeyFromAddress(accountAddress)
result := ed25519.Verify(accountPublicKey, payload, signature)
return result
}
}
159 changes: 51 additions & 108 deletions common/crypto/signature_test.go
Original file line number Diff line number Diff line change
@@ -1,122 +1,70 @@
package crypto

import (
"database/sql"
"reflect"
"regexp"
"testing"

"github.com/DATA-DOG/go-sqlmock"

"github.com/zoobc/zoobc-core/common/query"
)

func TestNewSignature(t *testing.T) {
type args struct {
executor query.ExecutorInterface
}
tests := []struct {
name string
args args
want *Signature
}{
{
name: "NewSignature:success",
args: args{
executor: nil,
},
want: &Signature{
Executor: nil,
},
want: &Signature{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewSignature(tt.args.executor); !reflect.DeepEqual(got, tt.want) {
if got := NewSignature(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewSignature() = %v, want %v", got, tt.want)
}
})
}
}

type mockSignatureSignExecutorSuccess struct {
query.Executor
}

func (*mockSignatureSignExecutorSuccess) ExecuteSelect(qe string, args ...interface{}) (*sql.Rows, error) {
db, mock, _ := sqlmock.New()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, account_type, address FROM account`)).WillReturnRows(sqlmock.NewRows([]string{
"ID", "AccountType", "Address"}).
AddRow([]byte{7, 205, 139, 247, 101, 123, 250, 42, 95, 96, 199, 181, 108, 85, 197, 164, 168, 36, 49, 12, 251, 252,
209, 82, 181, 112, 94, 41, 107, 240, 83, 180}, 0, "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgs="))
defer db.Close()
rows, _ := db.Query(qe)
return rows, nil
}

type mockSignatureSignExecutorFail struct {
query.Executor
}

func (*mockSignatureSignExecutorFail) ExecuteSelect(qe string, args ...interface{}) (*sql.Rows, error) {
db, mock, _ := sqlmock.New()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, account_type, address FROM account`)).WillReturnRows(sqlmock.NewRows([]string{
"ID", "AccountType", "Address"}))
defer db.Close()
rows, _ := db.Query(qe)
return rows, nil
}

func TestSignature_Sign(t *testing.T) {
type fields struct {
Executor query.ExecutorInterface
}
type args struct {
payload []byte
accountID []byte
seed string
payload []byte
accountType uint32
accountAddress string
seed string
}
tests := []struct {
name string
fields fields
args args
want []byte
name string
args args
want []byte
}{
{
name: "Sign:valid",
fields: fields{
Executor: &mockSignatureSignExecutorSuccess{},
},
args: args{
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
accountID: []byte{4, 38, 68, 24, 230, 247, 88, 220, 119, 124, 51, 149, 127, 214, 82, 224, 72, 239, 56, 139,
255, 81, 229, 184, 77, 80, 80, 39, 254, 173, 28, 169},
seed: "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved",
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
accountType: 0,
accountAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
seed: "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved",
},
want: []byte{42, 62, 47, 200, 180, 101, 85, 204, 179, 147, 143, 68, 30, 111, 6, 94, 81, 248, 219, 43, 90, 6, 167,
45, 132, 96, 130, 0, 153, 244, 159, 137, 159, 113, 78, 9, 164, 154, 213, 255, 17, 206, 153, 156, 176, 206, 33,
103, 72, 182, 228, 148, 234, 15, 176, 243, 50, 221, 106, 152, 53, 54, 173, 15},
},
{
name: "Sign:fail-{no account in account table}",
fields: fields{
Executor: &mockSignatureSignExecutorFail{},
},
name: "Sign:valid-{default type}",
args: args{
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
accountID: []byte{4, 38, 68, 24, 230, 247, 88, 220, 119, 124, 51, 149, 127, 214, 82, 224, 72, 239, 56, 139,
255, 81, 229, 184, 77, 80, 80, 39, 254, 173, 28, 169},
seed: "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved",
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
accountType: 1000,
accountAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
seed: "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved",
},
want: nil,
want: []byte{42, 62, 47, 200, 180, 101, 85, 204, 179, 147, 143, 68, 30, 111, 6, 94, 81, 248, 219, 43, 90, 6, 167,
45, 132, 96, 130, 0, 153, 244, 159, 137, 159, 113, 78, 9, 164, 154, 213, 255, 17, 206, 153, 156, 176, 206, 33,
103, 72, 182, 228, 148, 234, 15, 176, 243, 50, 221, 106, 152, 53, 54, 173, 15},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &Signature{
Executor: tt.fields.Executor,
}
got := s.Sign(tt.args.payload, tt.args.accountID, tt.args.seed)
s := &Signature{}
got := s.Sign(tt.args.payload, tt.args.accountType, tt.args.accountAddress, tt.args.seed)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Signature.Sign() = %v, want %v", got, tt.want)
}
@@ -125,24 +73,17 @@ func TestSignature_Sign(t *testing.T) {
}

func TestSignature_SignBlock(t *testing.T) {
type fields struct {
Executor *query.Executor
}
type args struct {
payload []byte
nodeSeed string
}
tests := []struct {
name string
fields fields
args args
want []byte
name string
args args
want []byte
}{
{
name: "SignBlock:success",
fields: fields{
Executor: nil, // todo: update when node-registration integrated
},
args: args{
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
nodeSeed: "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved",
@@ -154,9 +95,7 @@ func TestSignature_SignBlock(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &Signature{
Executor: tt.fields.Executor,
}
s := &Signature{}
if got := s.SignBlock(tt.args.payload, tt.args.nodeSeed); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Signature.SignBlock() = %v, want %v", got, tt.want)
}
@@ -165,42 +104,46 @@ func TestSignature_SignBlock(t *testing.T) {
}

func TestSignature_VerifySignature(t *testing.T) {
type fields struct {
Executor *query.Executor
}
type args struct {
payload []byte
signature []byte
accountID []byte
payload []byte
signature []byte
accountType uint32
accountAddress string
}
tests := []struct {
name string
fields fields
args args
want bool
name string
args args
want bool
}{
{
name: "VerifySignature:success", // todo: add fail:test after account integrated.
fields: fields{
Executor: nil, // todo: update this after account integrated
name: "VerifySignature:success",
args: args{
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
accountType: 0,
accountAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
signature: []byte{42, 62, 47, 200, 180, 101, 85, 204, 179, 147, 143, 68, 30, 111, 6, 94, 81, 248, 219, 43, 90, 6, 167,
45, 132, 96, 130, 0, 153, 244, 159, 137, 159, 113, 78, 9, 164, 154, 213, 255, 17, 206, 153, 156, 176, 206, 33,
103, 72, 182, 228, 148, 234, 15, 176, 243, 50, 221, 106, 152, 53, 54, 173, 15},
},
want: true,
},
{
name: "VerifySignature:success-{default}",
args: args{
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
payload: []byte{12, 43, 65, 65, 12, 123, 43, 12, 1, 24, 5, 5, 12, 54},
accountType: 10000,
accountAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
signature: []byte{42, 62, 47, 200, 180, 101, 85, 204, 179, 147, 143, 68, 30, 111, 6, 94, 81, 248, 219, 43, 90, 6, 167,
45, 132, 96, 130, 0, 153, 244, 159, 137, 159, 113, 78, 9, 164, 154, 213, 255, 17, 206, 153, 156, 176, 206, 33,
103, 72, 182, 228, 148, 234, 15, 176, 243, 50, 221, 106, 152, 53, 54, 173, 15},
accountID: []byte{4, 38, 68, 24, 230, 247, 88, 220, 119, 124, 51, 149, 127, 214, 82, 224, 72, 239, 56, 139,
255, 81, 229, 184, 77, 80, 80, 39, 254, 173, 28, 169},
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &Signature{
Executor: tt.fields.Executor,
}
if got := s.VerifySignature(tt.args.payload, tt.args.signature, tt.args.accountID); got != tt.want {
s := &Signature{}
if got := s.VerifySignature(tt.args.payload, tt.args.signature, tt.args.accountType, tt.args.accountAddress); got != tt.want {
t.Errorf("Signature.VerifySignature() = %v, want %v", got, tt.want)
}
})
1 change: 1 addition & 0 deletions common/database/migration.go
Original file line number Diff line number Diff line change
@@ -63,6 +63,7 @@ func (m *Migration) Init(qe *query.Executor) error {
"transaction_body_length" INTEGER,
"transaction_body_bytes" BLOB,
"signature" BLOB,
"version" INTEGER,
PRIMARY KEY("id")
);`,
`
105 changes: 55 additions & 50 deletions common/model/accountBalance.pb.go
27 changes: 21 additions & 6 deletions common/query/accountBalanceQuery.go
Original file line number Diff line number Diff line change
@@ -19,6 +19,8 @@ type (
GetAccountBalanceByAccountID() string
UpdateAccountBalance(fields, causedFields map[string]interface{}) (str string, args []interface{})
InsertAccountBalance(accountBalance *model.AccountBalance) (str string, args []interface{})
AddAccountBalance(balance int64, causedFields map[string]interface{}) (str string, args []interface{})
AddAccountSpendableBalance(balance int64, causedFields map[string]interface{}) (str string, args []interface{})
}
)

@@ -31,6 +33,7 @@ func NewAccountBalanceQuery() *AccountBalanceQuery {
"spendable_balance",
"balance",
"pop_revenue",
"latest",
},
TableName: "account_balance",
}
@@ -43,6 +46,17 @@ func (q *AccountBalanceQuery) GetAccountBalanceByAccountID() string {
`, strings.Join(q.Fields, ","), q.TableName)
}

func (q *AccountBalanceQuery) AddAccountBalance(balance int64, causedFields map[string]interface{}) (str string, args []interface{}) {
return fmt.Sprintf("UPDATE %s SET balance = balance + (%d), spendable_balance = spendable_balance + (%d) WHERE account_id = ?",
q.TableName, balance, balance), []interface{}{causedFields["account_id"]}
}

func (q *AccountBalanceQuery) AddAccountSpendableBalance(balance int64, causedFields map[string]interface{}) (
str string, args []interface{}) {
return fmt.Sprintf("UPDATE %s SET spendable_balance = spendable_balance + (%d) WHERE account_id = ?",
q.TableName, balance), []interface{}{causedFields["account_id"]}
}

func (q *AccountBalanceQuery) UpdateAccountBalance(fields, causedFields map[string]interface{}) (str string, args []interface{}) {

var (
@@ -55,18 +69,18 @@ func (q *AccountBalanceQuery) UpdateAccountBalance(fields, causedFields map[stri
`, q.TableName))

for k, v := range fields {
buff.WriteString(fmt.Sprintf("%s = ?", k))
if i < len(fields) {
buff.WriteString(fmt.Sprintf("%s = ? ", k))
if i < len(fields) && len(fields) > 1 {
buff.WriteString(",")
}
args = append(args, v)
i++
}

buff.WriteString("WHERE")
buff.WriteString("WHERE ")
for k, v := range causedFields {
buff.WriteString(fmt.Sprintf("%s = ?", k))
if j < len(causedFields) {
if j < len(causedFields) && len(causedFields) > 1 {
buff.WriteString(" AND")
}
j++
@@ -88,9 +102,10 @@ func (q *AccountBalanceQuery) InsertAccountBalance(accountBalance *model.Account
func (*AccountBalanceQuery) ExtractModel(account *model.AccountBalance) []interface{} {
return []interface{}{
account.AccountID,
account.Balance,
account.SpendableBalance,
account.BlockHeight,
account.SpendableBalance,
account.Balance,
account.PopRevenue,
account.Latest,
}
}
2 changes: 1 addition & 1 deletion common/query/mempoolQuery.go
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ type (
func NewMempoolQuery(chaintype contract.ChainType) *MempoolQuery {
return &MempoolQuery{
Fields: []string{
"ID", "FeePerByte", "ArrivalTimestamp", "TransactionBytes",
"id", "fee_per_byte", "arrival_timestamp", "transaction_bytes",
},
TableName: "mempool",
ChainType: chaintype,
52 changes: 35 additions & 17 deletions common/query/transactionQuery.go
Original file line number Diff line number Diff line change
@@ -3,8 +3,12 @@ package query
import (
"database/sql"
"fmt"
"math/big"
"strings"

"github.com/zoobc/zoobc-core/core/util"
"golang.org/x/crypto/sha3"

"github.com/zoobc/zoobc-core/common/contract"
"github.com/zoobc/zoobc-core/common/model"
)
@@ -41,6 +45,7 @@ func NewTransactionQuery(chaintype contract.ChainType) *TransactionQuery {
"transaction_body_length",
"transaction_body_bytes",
"signature",
"version",
},
TableName: "\"transaction\"",
ChainType: chaintype,
@@ -91,31 +96,44 @@ func (tq *TransactionQuery) InsertTransaction(tx *model.Transaction) (str string

// ExtractModel extract the model struct fields to the order of TransactionQuery.Fields
func (*TransactionQuery) ExtractModel(tx *model.Transaction) []interface{} {
digest := sha3.New512()
txBytes, _ := util.GetTransactionBytes(tx, true)
_, _ = digest.Write(txBytes)
hash := digest.Sum([]byte{})
res := new(big.Int)
txID := res.SetBytes([]byte{
hash[7],
hash[6],
hash[5],
hash[4],
hash[3],
hash[2],
hash[1],
hash[0],
}).Int64()
return []interface{}{
txID,
&tx.BlockID,
&tx.Height,
&tx.SenderAccountType,
&tx.SenderAccountAddress,
&tx.RecipientAccountType,
&tx.RecipientAccountAddress,
&tx.TransactionType,
&tx.Fee,
&tx.Timestamp,
&tx.TransactionHash,
&tx.TransactionBodyLength,
&tx.TransactionBodyBytes,
&tx.Signature,
tx.Version,
tx.ID,
tx.BlockID,
tx.Height,
tx.SenderAccountType,
tx.SenderAccountAddress,
tx.RecipientAccountType,
tx.RecipientAccountAddress,
tx.TransactionType,
tx.Fee,
tx.Timestamp,
tx.TransactionHash,
tx.TransactionBodyLength,
tx.TransactionBodyBytes,
tx.TransactionBody,
tx.Signature,
}
}

func (*TransactionQuery) BuildModel(blocks []*model.Transaction, rows *sql.Rows) []*model.Transaction {
for rows.Next() {
var tx model.Transaction
_ = rows.Scan(
&tx.Version,
&tx.ID,
&tx.BlockID,
&tx.Height,
@@ -129,8 +147,8 @@ func (*TransactionQuery) BuildModel(blocks []*model.Transaction, rows *sql.Rows)
&tx.TransactionHash,
&tx.TransactionBodyLength,
&tx.TransactionBodyBytes,
&tx.TransactionBody,
&tx.Signature,
&tx.Version,
)
blocks = append(blocks, &tx)
}
12 changes: 6 additions & 6 deletions common/query/transactionQuery_test.go
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ func TestGetTransaction(t *testing.T) {
params: &paramsStruct{},
want: "SELECT id, block_id, block_height, sender_account_type, sender_account_address, " +
"recipient_account_type, recipient_account_address, transaction_type, fee, timestamp, " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature from \"transaction\"",
"transaction_hash, transaction_body_length, transaction_body_bytes, signature, version from \"transaction\"",
},
{
name: "transaction query with ID param only",
@@ -32,7 +32,7 @@ func TestGetTransaction(t *testing.T) {
},
want: "SELECT id, block_id, block_height, sender_account_type, sender_account_address, " +
"recipient_account_type, recipient_account_address, transaction_type, fee, timestamp, " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature from \"transaction\" " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature, version from \"transaction\" " +
"WHERE id = 1",
},
}
@@ -65,7 +65,7 @@ func TestGetTransactions(t *testing.T) {
params: &paramsStruct{},
want: "SELECT id, block_id, block_height, sender_account_type, sender_account_address, " +
"recipient_account_type, recipient_account_address, transaction_type, fee, timestamp, " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature from " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature, version from " +
"\"transaction\" ORDER BY block_height, timestamp LIMIT 0,10",
},
{
@@ -75,7 +75,7 @@ func TestGetTransactions(t *testing.T) {
},
want: "SELECT id, block_id, block_height, sender_account_type, sender_account_address, " +
"recipient_account_type, recipient_account_address, transaction_type, fee, timestamp, " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature from " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature, version from " +
"\"transaction\" ORDER BY block_height, timestamp LIMIT 0,10",
},
{
@@ -85,7 +85,7 @@ func TestGetTransactions(t *testing.T) {
},
want: "SELECT id, block_id, block_height, sender_account_type, sender_account_address, " +
"recipient_account_type, recipient_account_address, transaction_type, fee, timestamp, " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature from " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature, version from " +
"\"transaction\" ORDER BY block_height, timestamp LIMIT 20,10",
},
{
@@ -96,7 +96,7 @@ func TestGetTransactions(t *testing.T) {
},
want: "SELECT id, block_id, block_height, sender_account_type, sender_account_address, " +
"recipient_account_type, recipient_account_address, transaction_type, fee, timestamp, " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature from " +
"transaction_hash, transaction_body_length, transaction_body_bytes, signature, version from " +
"\"transaction\" ORDER BY block_height, timestamp LIMIT 20,10",
},
}
114 changes: 65 additions & 49 deletions common/transaction/sendMoney.go
Original file line number Diff line number Diff line change
@@ -34,62 +34,91 @@ __If Not Genesis__:
`sender.balance` = current - amount
*/
func (tx *SendMoney) ApplyConfirmed() error {

// todo: undo apply unconfirmed for non-genesis transaction
var (
accountBalance model.AccountBalance
account model.Account
err error
recipientAccountBalance model.AccountBalance
recipientAccount model.Account
senderAccountBalance model.AccountBalance
senderAccount model.Account
err error
)

if err := tx.Validate(); err != nil {
return err
}

recipientAccount = model.Account{
ID: util.CreateAccountIDFromAddress(tx.RecipientAccountType, tx.RecipientAddress),
AccountType: tx.RecipientAccountType,
Address: tx.RecipientAddress,
}
senderAccount = model.Account{
ID: util.CreateAccountIDFromAddress(tx.SenderAccountType, tx.SenderAddress),
AccountType: tx.SenderAccountType,
Address: tx.SenderAddress,
}

if tx.Height == 0 {
account = model.Account{
ID: util.CreateAccountIDFromAddress(tx.RecipientAccountType, tx.RecipientAddress),
AccountType: tx.RecipientAccountType,
Address: tx.RecipientAddress,
senderAccountQ, senderAccountArgs := tx.AccountQuery.GetAccountByID(senderAccount.ID)
senderAccountRows, _ := tx.QueryExecutor.ExecuteSelect(senderAccountQ, senderAccountArgs...)
if !senderAccountRows.Next() { // genesis account not created yet
senderAccountBalance = model.AccountBalance{
AccountID: senderAccount.ID,
BlockHeight: tx.Height,
SpendableBalance: 0,
Balance: 0,
PopRevenue: 0,
Latest: true,
}
senderAccountInsertQ, senderAccountInsertArgs := tx.AccountQuery.InsertAccount(&senderAccount)
senderAccountBalanceInsertQ, senderAccountBalanceInsertArgs := tx.AccountBalanceQuery.InsertAccountBalance(&senderAccountBalance)
_, err = tx.QueryExecutor.ExecuteTransactionStatements(map[*string][]interface{}{
&senderAccountInsertQ: senderAccountInsertArgs,
&senderAccountBalanceInsertQ: senderAccountBalanceInsertArgs,
})
if err != nil {
return err
}
}
accountBalance = model.AccountBalance{
AccountID: account.ID,
_ = senderAccountRows.Close()
recipientAccountBalance = model.AccountBalance{
AccountID: recipientAccount.ID,
BlockHeight: tx.Height,
SpendableBalance: tx.Body.GetAmount(),
Balance: tx.Body.GetAmount(),
PopRevenue: 0,
Latest: true,
}
accountQ, accountQArgs := tx.AccountQuery.InsertAccount(&account)
accountBalanceQ, accountBalanceArgs := tx.AccountBalanceQuery.InsertAccountBalance(&accountBalance)
accountQ, accountQArgs := tx.AccountQuery.InsertAccount(&recipientAccount)
accountBalanceQ, accountBalanceArgs := tx.AccountBalanceQuery.InsertAccountBalance(&recipientAccountBalance)
// update sender
accountBalanceSenderQ, accountBalanceSenderQArgs := tx.AccountBalanceQuery.AddAccountBalance(
-tx.Body.GetAmount(),
map[string]interface{}{
"account_id": senderAccount.ID,
},
)
_, err = tx.QueryExecutor.ExecuteTransactionStatements(map[*string][]interface{}{
&accountQ: accountQArgs,
&accountBalanceQ: accountBalanceArgs,
&accountQ: accountQArgs,
&accountBalanceQ: accountBalanceArgs,
&accountBalanceSenderQ: accountBalanceSenderQArgs,
})
if err != nil {
return err
}
} else {
// update recipient
accountBalanceRecipientQ, accountBalanceRecipientQArgs := tx.AccountBalanceQuery.UpdateAccountBalance(
map[string]interface{}{
"balance": fmt.Sprintf("balance + %d", tx.Body.GetAmount()),
},
accountBalanceRecipientQ, accountBalanceRecipientQArgs := tx.AccountBalanceQuery.AddAccountBalance(
tx.Body.Amount,
map[string]interface{}{
"account_id": util.CreateAccountIDFromAddress(
tx.RecipientAccountType,
tx.RecipientAddress,
),
"account_id": recipientAccount.ID,
},
)
// update sender
accountBalanceSenderQ, accountBalanceSenderQArgs := tx.AccountBalanceQuery.UpdateAccountBalance(
accountBalanceSenderQ, accountBalanceSenderQArgs := tx.AccountBalanceQuery.AddAccountBalance(
-tx.Body.Amount,
map[string]interface{}{
"balance": fmt.Sprintf("balance - %d", tx.Body.GetAmount()),
},
map[string]interface{}{
"account_id": util.CreateAccountIDFromAddress(
tx.SenderAccountType,
tx.SenderAddress,
),
"account_id": senderAccount.ID,
},
)
_, err = tx.QueryExecutor.ExecuteTransactionStatements(map[*string][]interface{}{
@@ -117,23 +146,9 @@ func (tx *SendMoney) ApplyUnconfirmed() error {
return err
}

// update recipient
accountBalanceRecipientQ, accountBalanceRecipientQArgs := tx.AccountBalanceQuery.UpdateAccountBalance(
map[string]interface{}{
"account_balance": fmt.Sprintf("account_balance + %d", tx.Body.GetAmount()),
},
map[string]interface{}{
"account_id": util.CreateAccountIDFromAddress(
tx.RecipientAccountType,
tx.RecipientAddress,
),
},
)
// update sender
accountBalanceSenderQ, accountBalanceSenderQArgs := tx.AccountBalanceQuery.UpdateAccountBalance(
map[string]interface{}{
"account_balance": fmt.Sprintf("account_balance - %d", tx.Body.GetAmount()),
},
accountBalanceSenderQ, accountBalanceSenderQArgs := tx.AccountBalanceQuery.AddAccountSpendableBalance(
-tx.Body.Amount,
map[string]interface{}{
"account_id": util.CreateAccountIDFromAddress(
tx.SenderAccountType,
@@ -142,8 +157,7 @@ func (tx *SendMoney) ApplyUnconfirmed() error {
},
)
_, err = tx.QueryExecutor.ExecuteTransactionStatements(map[*string][]interface{}{
&accountBalanceSenderQ: accountBalanceSenderQArgs,
&accountBalanceRecipientQ: accountBalanceRecipientQArgs,
&accountBalanceSenderQ: accountBalanceSenderQArgs,
})
if err != nil {
return err
@@ -204,6 +218,7 @@ func (tx *SendMoney) Validate() error {
&accountBalance.SpendableBalance,
&accountBalance.Balance,
&accountBalance.PopRevenue,
&accountBalance.Latest,
)
}

@@ -217,7 +232,8 @@ func (tx *SendMoney) Validate() error {
func (tx *SendMoney) GetAmount() int64 {
return tx.Body.Amount
}

func (*SendMoney) GetSize() uint32 {
// only amount (int64)
return uint32(8)
return 8
}
127 changes: 125 additions & 2 deletions common/transaction/sendMoney_test.go
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ package transaction

import (
"database/sql"
"errors"
"regexp"
"testing"

@@ -28,6 +29,22 @@ type (
executorApplySuccess struct {
executorValidateSuccess
}

executorGenesisSuccess struct {
query.Executor
}

executorGenesisSuccessCreateAccount struct {
executorGenesisSuccess
}

executorGenesisFail struct {
executorGenesisSuccessCreateAccount
}

executorGenesisFailAddBalance struct {
executorGenesisSuccess
}
)

func (*executorApplySuccess) ExecuteTransactionStatements(queries map[*string][]interface{}) ([]sql.Result, error) {
@@ -65,7 +82,7 @@ func (*executorValidateSuccess) ExecuteSelect(qStr string, args ...interface{})

mock.ExpectQuery(regexp.QuoteMeta(qStr)).WithArgs(1).WillReturnRows(sqlmock.NewRows(
query.NewAccountBalanceQuery().Fields,
).AddRow(1, 2, 50, 50, 0))
).AddRow(1, 2, 50, 50, 0, 1))
return db.Query(qStr, 1)
}
func (*executorValidateSuccess) ExecuteTransactionStatements(queries map[*string][]interface{}) ([]sql.Result, error) {
@@ -149,10 +166,48 @@ func (*executorAccountCountSuccess) ExecuteSelect(qStr string, args ...interface

mock.ExpectQuery(regexp.QuoteMeta(qStr)).WithArgs(1).WillReturnRows(sqlmock.NewRows(
query.NewAccountBalanceQuery().Fields,
).AddRow(1, 2, 3, 4, 5))
).AddRow(1, 2, 3, 4, 5, 6))
return db.Query(qStr, 1)
}

func (*executorGenesisSuccess) ExecuteSelect(qStr string, args ...interface{}) (*sql.Rows, error) {
db, mock, err := sqlmock.New()
if err != nil {
return nil, err
}
defer db.Close()

mock.ExpectQuery(regexp.QuoteMeta(qStr)).WithArgs(args[0]).WillReturnRows(sqlmock.NewRows([]string{
"AccountID", "AccountType", "AccountAddress"},
).AddRow([]byte{}, 0, ""))
return db.Query(qStr, args[0])
}

func (*executorGenesisSuccess) ExecuteTransactionStatements(queries map[*string][]interface{}) ([]sql.Result, error) {
return nil, nil
}

func (*executorGenesisSuccessCreateAccount) ExecuteSelect(qStr string, args ...interface{}) (*sql.Rows, error) {
db, mock, err := sqlmock.New()
if err != nil {
return nil, err
}
defer db.Close()

mock.ExpectQuery(regexp.QuoteMeta(qStr)).WithArgs(args[0]).WillReturnRows(sqlmock.NewRows([]string{
"AccountID", "AccountType", "AccountAddress"},
))
return db.Query(qStr, args[0])
}

func (*executorGenesisFail) ExecuteTransactionStatements(queries map[*string][]interface{}) ([]sql.Result, error) {
return nil, errors.New("mockedError")
}

func (*executorGenesisFailAddBalance) ExecuteTransactionStatements(queries map[*string][]interface{}) ([]sql.Result, error) {
return nil, errors.New("mockedError")
}

func TestSendMoney_Validate(t *testing.T) {
type fields struct {
Body *model.SendMoneyTransactionBody
@@ -456,6 +511,74 @@ func TestSendMoney_ApplyConfirmed(t *testing.T) {
},
wantErr: true,
},
{
name: "wantSuccess:genesis-{genesis-sender-exist}",
fields: fields{
Body: &model.SendMoneyTransactionBody{
Amount: 10,
},
Height: 0,
SenderAccountType: 0,
SenderAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
RecipientAccountType: 0,
RecipientAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
AccountQuery: query.NewAccountQuery(),
AccountBalanceQuery: query.NewAccountBalanceQuery(),
QueryExecutor: &executorGenesisSuccess{},
},
wantErr: false,
},
{
name: "wantSuccess:genesis-{genesis-sender-not-exist, create genesis}",
fields: fields{
Body: &model.SendMoneyTransactionBody{
Amount: 10,
},
Height: 0,
SenderAccountType: 0,
SenderAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
RecipientAccountType: 0,
RecipientAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
AccountQuery: query.NewAccountQuery(),
AccountBalanceQuery: query.NewAccountBalanceQuery(),
QueryExecutor: &executorGenesisSuccessCreateAccount{},
},
wantErr: false,
},
{
name: "wantFail:genesis-{genesis-sender-not-exist, create genesis fail}",
fields: fields{
Body: &model.SendMoneyTransactionBody{
Amount: 10,
},
Height: 0,
SenderAccountType: 0,
SenderAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
RecipientAccountType: 0,
RecipientAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
AccountQuery: query.NewAccountQuery(),
AccountBalanceQuery: query.NewAccountBalanceQuery(),
QueryExecutor: &executorGenesisFail{},
},
wantErr: true,
},
{
name: "wantFail:genesis-{genesis add balance fail}",
fields: fields{
Body: &model.SendMoneyTransactionBody{
Amount: 10,
},
Height: 0,
SenderAccountType: 0,
SenderAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
RecipientAccountType: 0,
RecipientAddress: "BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE",
AccountQuery: query.NewAccountQuery(),
AccountBalanceQuery: query.NewAccountBalanceQuery(),
QueryExecutor: &executorGenesisFailAddBalance{},
},
wantErr: true,
},
{
name: "wantSuccess:Create",
fields: fields{
6 changes: 5 additions & 1 deletion common/transaction/transaction.go
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ package transaction

import (
"github.com/zoobc/zoobc-core/common/model"
"github.com/zoobc/zoobc-core/common/query"
"github.com/zoobc/zoobc-core/common/util"
)

@@ -15,7 +16,7 @@ type (
}
)

func GetTransactionType(tx *model.Transaction) TypeAction {
func GetTransactionType(tx *model.Transaction, executor query.ExecutorInterface) TypeAction {

buf := util.ConvertUint32ToBytes(tx.GetTransactionType())
switch buf[0] {
@@ -36,6 +37,9 @@ func GetTransactionType(tx *model.Transaction) TypeAction {
RecipientAddress: tx.GetRecipientAccountAddress(),
RecipientAccountType: tx.GetRecipientAccountType(),
Height: tx.GetHeight(),
AccountQuery: query.NewAccountQuery(),
AccountBalanceQuery: query.NewAccountBalanceQuery(),
QueryExecutor: executor,
}
default:
return nil
15 changes: 13 additions & 2 deletions common/transaction/transaction_test.go
Original file line number Diff line number Diff line change
@@ -5,12 +5,15 @@ import (
"reflect"
"testing"

"github.com/zoobc/zoobc-core/common/query"

"github.com/zoobc/zoobc-core/common/model"
)

func TestGetTransactionType(t *testing.T) {
type args struct {
tx *model.Transaction
tx *model.Transaction
executor query.ExecutorInterface
}
tests := []struct {
name string
@@ -33,6 +36,7 @@ func TestGetTransactionType(t *testing.T) {
},
TransactionType: binary.LittleEndian.Uint32([]byte{1, 0, 0, 0}),
},
executor: nil,
},
want: TypeAction(&SendMoney{
Height: 0,
@@ -43,6 +47,9 @@ func TestGetTransactionType(t *testing.T) {
Body: &model.SendMoneyTransactionBody{
Amount: 10,
},
QueryExecutor: nil,
AccountBalanceQuery: query.NewAccountBalanceQuery(),
AccountQuery: query.NewAccountQuery(),
}),
},
{
@@ -61,6 +68,7 @@ func TestGetTransactionType(t *testing.T) {
},
TransactionType: binary.LittleEndian.Uint32([]byte{0, 0, 0, 0}),
},
executor: nil,
},
want: TypeAction(&TXEmpty{}),
},
@@ -80,6 +88,7 @@ func TestGetTransactionType(t *testing.T) {
},
TransactionType: binary.LittleEndian.Uint32([]byte{0, 1, 0, 0}),
},
executor: nil,
},
},
{
@@ -98,6 +107,7 @@ func TestGetTransactionType(t *testing.T) {
},
TransactionType: binary.LittleEndian.Uint32([]byte{1, 1, 0, 0}),
},
executor: nil,
},
},
{
@@ -116,12 +126,13 @@ func TestGetTransactionType(t *testing.T) {
},
TransactionType: binary.LittleEndian.Uint32([]byte{2, 1, 0, 0}),
},
executor: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetTransactionType(tt.args.tx); !reflect.DeepEqual(got, tt.want) {
if got := GetTransactionType(tt.args.tx, tt.args.executor); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetTransactionType() = %v, want %v", got, tt.want)
}
})
15 changes: 15 additions & 0 deletions common/util/account.go
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import (
"encoding/base64"
"encoding/binary"
"errors"
"fmt"

"golang.org/x/crypto/ed25519"

@@ -71,6 +72,20 @@ func GetAddressFromPublicKey(publicKey []byte) (string, error) {
return address, nil
}

// GetPublicKeyFromAddress Get the raw public key from a formatted address
func GetPublicKeyFromAddress(address string) ([]byte, error) {
// decode base64 back to byte
publicKey, err := base64.URLEncoding.DecodeString(address)
if err != nil {
return nil, err
}
// Needs to check the checksum bit at the end, and if valid,
if publicKey[32] != GetChecksumByte(publicKey[:32]) {
return nil, fmt.Errorf("address checksum failed")
}
return publicKey[:32], nil
}

// GetChecksumByte Calculate a checksum byte from a collection of bytes
// checksum 255 = 255, 256 = 0, 257 = 1 and so on.
func GetChecksumByte(bytes []byte) byte {
79 changes: 79 additions & 0 deletions common/util/account_test.go
Original file line number Diff line number Diff line change
@@ -152,3 +152,82 @@ func TestGetAddressFromPublicKey(t *testing.T) {
})
}
}

func TestGetPublicKeyFromAddress(t *testing.T) {
type args struct {
address string
}
tests := []struct {
name string
args args
want []byte
wantErr bool
}{
{
name: "GetPublicKeyFromAddress:success",
args: args{
address: "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgtN",
},
want: []byte{4, 38, 103, 73, 250, 169, 63, 155, 106, 21, 9, 76, 77, 137, 3, 120, 21, 69, 90, 118, 242,
84, 174, 239, 46, 190, 78, 68, 90, 83, 142, 11},
wantErr: false,
},
{
name: "GetPublicKeyFromAddress:fail-{decode error, wrong address format/length}",
args: args{
address: "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgt",
},
want: nil,
wantErr: true,
},
{
name: "GetPublicKeyFromAddress:fail-{checksum error, wrong address format}",
args: args{
address: "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgtM",
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetPublicKeyFromAddress(tt.args.address)
if (err != nil) != tt.wantErr {
t.Errorf("GetPublicKeyFromAddress() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetPublicKeyFromAddress() = %v, want %v", got, tt.want)
}
})
}
}

func TestCreateAccountIDFromAddress(t *testing.T) {
type args struct {
accountType uint32
address string
}
tests := []struct {
name string
args args
want []byte
}{
{
name: "CreateAccountIDFromAddress:success",
args: args{
accountType: 0,
address: "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgtN",
},
want: []byte{136, 106, 141, 253, 44, 34, 145, 81, 166, 229, 33, 209, 150, 188, 204, 28, 239, 33, 152, 158, 4, 187,
13, 109, 173, 223, 169, 232, 50, 200, 169, 25},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := CreateAccountIDFromAddress(tt.args.accountType, tt.args.address); !reflect.DeepEqual(got, tt.want) {
t.Errorf("CreateAccountIDFromAddress() = %v, want %v", got, tt.want)
}
})
}
}
27 changes: 27 additions & 0 deletions common/util/convert_test.go
Original file line number Diff line number Diff line change
@@ -243,3 +243,30 @@ func TestConvertIntToBytes(t *testing.T) {
})
}
}

func TestConvertStringToBytes(t *testing.T) {
type args struct {
str string
}
tests := []struct {
name string
args args
want []byte
}{
{
name: "ConvertStringToBytes:success",
args: args{
str: "dummy random string here",
},
want: []byte{24, 0, 0, 0, 100, 117, 109, 109, 121, 32, 114, 97, 110, 100, 111, 109, 32, 115, 116, 114, 105, 110, 103, 32,
104, 101, 114, 101},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ConvertStringToBytes(tt.args.str); !reflect.DeepEqual(got, tt.want) {
t.Errorf("ConvertStringToBytes() = %v, want %v", got, tt.want)
}
})
}
}
9 changes: 9 additions & 0 deletions common/util/loadConfig_test.go
Original file line number Diff line number Diff line change
@@ -32,6 +32,15 @@ func TestLoadConfig(t *testing.T) {
},
wantErr: true,
},
{
name: "MustError:{len path, name, or extension < 1}",
args: args{
path: "",
name: "",
extension: "",
},
wantErr: true,
},
}

for _, tt := range tests {
19 changes: 11 additions & 8 deletions core/service/blockCoreService.go
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ type (
transactions []*model.Transaction, payloadHash []byte, payloadLength uint32, secretPhrase string) *model.Block
NewGenesisBlock(version uint32, previousBlockHash []byte, blockSeed []byte, blocksmithID []byte,
hash string, previousBlockHeight uint32, timestamp int64, totalAmount int64, totalFee int64, totalCoinBase int64,
transactions []*model.Transaction, payloadHash []byte, smithScale int64, cumulativeDifficulty *big.Int,
transactions []*model.Transaction, payloadHash []byte, payloadLength uint32, smithScale int64, cumulativeDifficulty *big.Int,
genesisSignature []byte) *model.Block
PushBlock(previousBlock, block *model.Block) error
GetLastBlock() (*model.Block, error)
@@ -85,7 +85,7 @@ func (bs *BlockService) NewBlock(version uint32, previousBlockHash, blockSeed, b
// NewGenesisBlock create new block that is fixed in the value of cumulative difficulty, smith scale, and the block signature
func (bs *BlockService) NewGenesisBlock(version uint32, previousBlockHash, blockSeed, blocksmithID []byte,
hash string, previousBlockHeight uint32, timestamp, totalAmount, totalFee, totalCoinBase int64,
transactions []*model.Transaction, payloadHash []byte, smithScale int64, cumulativeDifficulty *big.Int,
transactions []*model.Transaction, payloadHash []byte, payloadLength uint32, smithScale int64, cumulativeDifficulty *big.Int,
genesisSignature []byte) *model.Block {
block := &model.Block{
Version: version,
@@ -98,6 +98,7 @@ func (bs *BlockService) NewGenesisBlock(version uint32, previousBlockHash, block
TotalFee: totalFee,
TotalCoinBase: totalCoinBase,
Transactions: transactions,
PayloadLength: payloadLength,
PayloadHash: payloadHash,
SmithScale: smithScale,
CumulativeDifficulty: cumulativeDifficulty.String(),
@@ -130,13 +131,12 @@ func (bs *BlockService) PushBlock(previousBlock, block *model.Block) error {
return err
}
fmt.Printf("got new block, %v", result)

// apply transactions and remove them from mempool
transactions := block.GetTransactions()
if len(transactions) > 0 {
for _, tx := range block.GetTransactions() {
err := transaction.GetTransactionType(tx).ApplyConfirmed()
if err != nil {
err := transaction.GetTransactionType(tx, bs.QueryExecutor).ApplyConfirmed() // todo: make this mockable
if err == nil {
tx.BlockID = block.ID
tx.Height = block.Height
transactionInsertQuery, transactionInsertValue := bs.TransactionQuery.InsertTransaction(tx)
@@ -146,16 +146,19 @@ func (bs *BlockService) PushBlock(previousBlock, block *model.Block) error {
}
}
}
if err := bs.RemoveMempoolTransactions(transactions); err != nil {
log.Errorf("Can't delete Mempool Transactions: %s", err)
return err
if block.Height != 0 {
if err := bs.RemoveMempoolTransactions(transactions); err != nil {
log.Errorf("Can't delete Mempool Transactions: %s", err)
return err
}
}
}
//TODO: commit db transaction here

// broadcast block

return nil

}

// GetLastBlock return the last pushed block
7 changes: 5 additions & 2 deletions core/service/blockCoreService_test.go
Original file line number Diff line number Diff line change
@@ -163,6 +163,7 @@ func TestBlockService_NewGenesisBlock(t *testing.T) {
totalCoinBase int64
transactions []*model.Transaction
payloadHash []byte
payloadLength uint32
smithScale int64
cumulativeDifficulty *big.Int
genesisSignature []byte
@@ -192,6 +193,7 @@ func TestBlockService_NewGenesisBlock(t *testing.T) {
totalCoinBase: 0,
transactions: []*model.Transaction{},
payloadHash: []byte{},
payloadLength: 8,
smithScale: 0,
cumulativeDifficulty: big.NewInt(1),
genesisSignature: []byte{},
@@ -207,6 +209,7 @@ func TestBlockService_NewGenesisBlock(t *testing.T) {
TotalCoinBase: 0,
Transactions: []*model.Transaction{},
PayloadHash: []byte{},
PayloadLength: 8,
SmithScale: 0,
CumulativeDifficulty: "1",
BlockSignature: []byte{},
@@ -219,8 +222,8 @@ func TestBlockService_NewGenesisBlock(t *testing.T) {
}
if got := b.NewGenesisBlock(test.args.version, test.args.previousBlockHash, test.args.blockSeed, test.args.blocksmithID,
test.args.hash, test.args.previousBlockHeight, test.args.timestamp, test.args.totalAmount, test.args.totalFee,
test.args.totalCoinBase, test.args.transactions, test.args.payloadHash, test.args.smithScale, test.args.cumulativeDifficulty,
test.args.genesisSignature); !reflect.DeepEqual(got, test.want) {
test.args.totalCoinBase, test.args.transactions, test.args.payloadHash, test.args.payloadLength, test.args.smithScale,
test.args.cumulativeDifficulty, test.args.genesisSignature); !reflect.DeepEqual(got, test.want) {
t.Errorf("BlockService.NewGenesisBlock() = %v, want %v", got, test.want)
}
}
55 changes: 55 additions & 0 deletions core/service/genesisCoreService.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package service

import (
"github.com/zoobc/zoobc-core/common/chaintype"
"github.com/zoobc/zoobc-core/common/contract"
"github.com/zoobc/zoobc-core/common/model"
"github.com/zoobc/zoobc-core/common/util"
)

var genesisFundReceiver = map[string]int64{ // address : amount | public key hex
"BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE": 10000000, // 04264418e6f758dc777c33957fd652e048ef388bff51e5b84d505027fead1ca9
"BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgtN": 10000000, // 04266749faa93f9b6a15094c4d89037815455a76f254aeef2ebe4e445a538e0b
"BCZKLvgUYZ1KKx-jtF9KoJskjVPvB9jpIjfzzI6zDW0J": 10000000, // 04264a2ef814619d4a2b1fa3b45f4aa09b248d53ef07d8e92237f3cc8eb30d6d
}

const genesisSender = "BCZD_VxfO2S9aziIL3cn_cXW7uPDVPOrnXuP98GEAUC7" // 042643fd5c5f3b64bd6b38882f7727fdc5d6eee3c354f3ab9d7b8ff7c1840140

var genesisSignature = []byte{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}

// GetGenesisTransactions return list of genesis transaction to be executed in the
// very beginning of running the blockchain
func GetGenesisTransactions(chainType contract.ChainType) []*model.Transaction {
genesisTxs := []*model.Transaction{}
switch chainType.(type) {
case *chaintype.MainChain:
for receiver, amount := range genesisFundReceiver {
genesisTxs = append(genesisTxs, &model.Transaction{
Version: 1,
TransactionType: util.ConvertBytesToUint32([]byte{1, 0, 0, 0}),
Height: 0,
Timestamp: 1562806389280,
SenderAccountType: 0,
SenderAccountAddress: genesisSender,
RecipientAccountType: 0,
RecipientAccountAddress: receiver,
Fee: 0,
TransactionBodyLength: 8,
TransactionBody: &model.Transaction_SendMoneyTransactionBody{
SendMoneyTransactionBody: &model.SendMoneyTransactionBody{
Amount: amount,
},
},
TransactionBodyBytes: util.ConvertUint64ToBytes(uint64(amount)),
Signature: genesisSignature,
})
}
return genesisTxs
default:
return nil
}

}
4 changes: 2 additions & 2 deletions core/service/mempoolCoreService.go
Original file line number Diff line number Diff line change
@@ -140,7 +140,7 @@ func (mps *MempoolService) ValidateMempoolTransaction(mpTx *model.MempoolTransac
return errors.New("InvalidTransactionID")
}

if err := transaction.GetTransactionType(tx).Validate(); err != nil {
if err := transaction.GetTransactionType(tx, mps.QueryExecutor).Validate(); err != nil {
return err
}

@@ -182,7 +182,7 @@ func (mps *MempoolService) SelectTransactionsFromMempool(blockTimestamp int64) (
continue
}

if err := transaction.GetTransactionType(tx).Validate(); err != nil {
if err := transaction.GetTransactionType(tx, mps.QueryExecutor).Validate(); err != nil {
continue
}

8 changes: 4 additions & 4 deletions core/service/mempoolCoreService_test.go
Original file line number Diff line number Diff line change
@@ -21,14 +21,14 @@ type mockMempoolQueryExecutorSuccess struct {
query.Executor
}

var getTxByIDQuery = "SELECT ID, FeePerByte, ArrivalTimestamp, TransactionBytes FROM mempool WHERE id = :id"
var getTxByIDQuery = "SELECT id, fee_per_byte, arrival_timestamp, transaction_bytes FROM mempool WHERE id = :id"

func (*mockMempoolQueryExecutorSuccess) ExecuteSelect(qe string, args ...interface{}) (*sql.Rows, error) {
db, mock, _ := sqlmock.New()
defer db.Close()
switch qe {
case "SELECT ID, FeePerByte, ArrivalTimestamp, TransactionBytes FROM mempool":
mockedRows := sqlmock.NewRows([]string{"ID", "FeePerByte", "ArrivalTimestamp", "TransactionBytes"})
case "SELECT id, fee_per_byte, arrival_timestamp, transaction_bytes FROM mempool":
mockedRows := sqlmock.NewRows([]string{"id", "fee_per_byte", "arrival_timestamp", "transaction_bytes"})
mockedRows.AddRow(1, 1, 1562893305, getTestSignedMempoolTransaction(1, 1562893305).TransactionBytes)
mockedRows.AddRow(2, 10, 1562893304, getTestSignedMempoolTransaction(2, 1562893304).TransactionBytes)
mockedRows.AddRow(3, 1, 1562893302, getTestSignedMempoolTransaction(3, 1562893302).TransactionBytes)
@@ -58,7 +58,7 @@ func (*mockMempoolQueryExecutorFail) ExecuteSelect(qe string, args ...interface{
// before adding mempool transactions to db we check for duplicate transactions
case getTxByIDQuery:
mock.ExpectQuery(regexp.QuoteMeta(qe)).WillReturnRows(sqlmock.NewRows([]string{
"ID", "FeePerByte", "ArrivalTimestamp", "TransactionBytes"},
"id", "fee_per_byte", "arrival_timestamp", "transaction_bytes"},
).AddRow(3, 1, 1562893302, []byte{}))
default:
return nil, errors.New("MockedError")
23 changes: 18 additions & 5 deletions core/smith/blockchainProcessor.go
Original file line number Diff line number Diff line change
@@ -15,8 +15,8 @@ import (
"github.com/zoobc/zoobc-core/common/constant"

"github.com/zoobc/zoobc-core/common/model"
"github.com/zoobc/zoobc-core/common/util"
"github.com/zoobc/zoobc-core/core/service"
"github.com/zoobc/zoobc-core/core/util"
coreUtil "github.com/zoobc/zoobc-core/core/util"
"golang.org/x/crypto/sha3"
)
@@ -166,14 +166,14 @@ func (bp *BlockchainProcessor) GenerateBlock(previousBlock *model.Block, secretP
}
digest := sha3.New512()
for _, mpTx := range mempoolTransactions {
tx, err := util.ParseTransactionBytes(mpTx.TransactionBytes, true)
tx, err := coreUtil.ParseTransactionBytes(mpTx.TransactionBytes, true)
if err != nil {
return nil, err
}

sortedTx = append(sortedTx, tx)
_, _ = digest.Write(mpTx.TransactionBytes)
txType := transaction.GetTransactionType(tx)
txType := transaction.GetTransactionType(tx, nil)
totalAmount += txType.GetAmount()
totalFee += tx.Fee
payloadLength += txType.GetSize()
@@ -203,11 +203,24 @@ func (bp *BlockchainProcessor) AddGenesis() error {
var totalAmount int64
var totalFee int64
var totalCoinBase int64
var payloadLength uint32
var blockTransactions []*model.Transaction
for _, tx := range service.GetGenesisTransactions(bp.Chaintype) {
txBytes, _ := coreUtil.GetTransactionBytes(tx, true)
_, _ = digest.Write(txBytes)
if tx.TransactionType == util.ConvertBytesToUint32([]byte{1, 0, 0, 0}) { // if type = send money
totalAmount += tx.GetSendMoneyTransactionBody().Amount
}
txType := transaction.GetTransactionType(tx, nil)
totalAmount += txType.GetAmount()
totalFee += tx.Fee
payloadLength += txType.GetSize()
blockTransactions = append(blockTransactions, tx)
}
payloadHash := digest.Sum([]byte{})
block := bp.BlockService.NewGenesisBlock(1, nil, make([]byte, 64), []byte{}, "",
0, constant.GenesisBlockTimestamp, totalAmount, totalFee, totalCoinBase, blockTransactions, payloadHash, constant.InitialSmithScale,
big.NewInt(0), constant.GenesisBlockSignature)
0, constant.GenesisBlockTimestamp, totalAmount, totalFee, totalCoinBase, blockTransactions, payloadHash, payloadLength,
constant.InitialSmithScale, big.NewInt(0), constant.GenesisBlockSignature)
// assign genesis block id
block.ID = coreUtil.GetBlockID(block)
err := bp.BlockService.PushBlock(&model.Block{ID: -1, Height: 0}, block)
4 changes: 2 additions & 2 deletions core/smith/blockchainProcessor_test.go
Original file line number Diff line number Diff line change
@@ -118,7 +118,7 @@ func (*mockBlockServiceSuccess) NewBlock(version uint32, previousBlockHash, bloc
}
func (*mockBlockServiceSuccess) NewGenesisBlock(version uint32, previousBlockHash, blockSeed, blocksmithID []byte,
hash string, previousBlockHeight uint32, timestamp, totalAmount, totalFee, totalCoinBase int64,
transactions []*model.Transaction, payloadHash []byte, smithScale int64, cumulativeDifficulty *big.Int,
transactions []*model.Transaction, payloadHash []byte, payloadLength uint32, smithScale int64, cumulativeDifficulty *big.Int,
genesisSignature []byte) *model.Block {
return &model.Block{
Version: 1,
@@ -131,7 +131,7 @@ func (*mockBlockServiceSuccess) NewGenesisBlock(version uint32, previousBlockHas
TotalCoinBase: 0,
Transactions: []*model.Transaction{},
PayloadHash: []byte{},
PayloadLength: 0,
PayloadLength: payloadLength,
SmithScale: 0,
CumulativeDifficulty: "1",
BlockSignature: []byte{},
2 changes: 2 additions & 0 deletions core/util/transactionUtil.go
Original file line number Diff line number Diff line change
@@ -134,6 +134,8 @@ func ParseTransactionBytes(transactionBytes []byte, sign bool) (*model.Transacti
}, nil
}

// ReadAccountAddress support different way to read the sender or recipient address depending on
// their types.
func ReadAccountAddress(accountType uint32, buf *bytes.Buffer) []byte {
switch accountType {
case 0:
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
@@ -81,7 +81,7 @@ func main() {
blockchainProcessor := smith.NewBlockchainProcessor(mainchain,
smith.NewBlocksmith(nodeSecretPhrase),
service.NewBlockService(mainchain, query.NewQueryExecutor(db), query.NewBlockQuery(mainchain),
query.NewMempoolQuery(mainchain), query.NewTransactionQuery(mainchain), crypto.NewSignature(queryExecutor)),
query.NewMempoolQuery(mainchain), query.NewTransactionQuery(mainchain), crypto.NewSignature()),
service.NewMempoolService(mainchain, query.NewQueryExecutor(db), query.NewMempoolQuery(mainchain)))
if !blockchainProcessor.CheckGenesis() { // Add genesis if not exist
_ = blockchainProcessor.AddGenesis()