Skip to content

Commit 2cd619f

Browse files
Merge pull request #96 from andy-shi88/40-post-transaction
API - Post Transaction
2 parents 1e714e0 + 3601fe7 commit 2cd619f

31 files changed

+1636
-421
lines changed

api/api.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import (
44
"fmt"
55
"net"
66

7+
"github.com/zoobc/zoobc-core/common/chaintype"
8+
core_service "github.com/zoobc/zoobc-core/core/service"
9+
10+
"github.com/zoobc/zoobc-core/common/crypto"
11+
"github.com/zoobc/zoobc-core/common/transaction"
12+
713
"github.com/sirupsen/logrus"
814
"github.com/zoobc/zoobc-core/api/handler"
915
"github.com/zoobc/zoobc-core/api/service"
@@ -25,10 +31,19 @@ func init() {
2531
}
2632
}
2733

28-
func startGrpcServer(port int, queryExecutor *query.Executor, p2pHostService contract.P2PType) {
34+
func startGrpcServer(port int, queryExecutor query.ExecutorInterface, p2pHostService contract.P2PType) {
2935
grpcServer := grpc.NewServer(
3036
grpc.UnaryInterceptor(util.NewServerInterceptor(apiLogger)),
3137
)
38+
actionTypeSwitcher := &transaction.TypeSwitcher{
39+
Executor: queryExecutor,
40+
}
41+
mempoolService := core_service.NewMempoolService(
42+
&chaintype.MainChain{},
43+
queryExecutor,
44+
query.NewMempoolQuery(&chaintype.MainChain{}),
45+
actionTypeSwitcher,
46+
query.NewAccountBalanceQuery())
3247

3348
serv, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
3449
if err != nil {
@@ -43,7 +58,13 @@ func startGrpcServer(port int, queryExecutor *query.Executor, p2pHostService con
4358

4459
// Set GRPC handler for Transactions requests
4560
rpc_service.RegisterTransactionServiceServer(grpcServer, &handler.TransactionHandler{
46-
Service: service.NewTransactionService(queryExecutor),
61+
Service: service.NewTransactionService(
62+
queryExecutor,
63+
&crypto.Signature{},
64+
actionTypeSwitcher,
65+
mempoolService,
66+
apiLogger,
67+
),
4768
})
4869

4970
// Set GRPC handler for Transactions requests
@@ -62,6 +83,6 @@ func startGrpcServer(port int, queryExecutor *query.Executor, p2pHostService con
6283
}
6384

6485
// Start starts api servers in the given port and passing query executor
65-
func Start(grpcPort, restPort int, queryExecutor *query.Executor, p2pHostService contract.P2PType) {
86+
func Start(grpcPort, restPort int, queryExecutor query.ExecutorInterface, p2pHostService contract.P2PType) {
6687
startGrpcServer(grpcPort, queryExecutor, p2pHostService)
6788
}

api/client/PostTransaction/client.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package main
2+
3+
import (
4+
"context"
5+
6+
log "github.com/sirupsen/logrus"
7+
rpc_model "github.com/zoobc/zoobc-core/common/model"
8+
rpc_service "github.com/zoobc/zoobc-core/common/service"
9+
"google.golang.org/grpc"
10+
)
11+
12+
func main() {
13+
conn, err := grpc.Dial(":3001", grpc.WithInsecure())
14+
if err != nil {
15+
log.Fatalf("did not connect: %s", err)
16+
}
17+
defer conn.Close()
18+
19+
c := rpc_service.NewTransactionServiceClient(conn)
20+
21+
response, err := c.PostTransaction(context.Background(), &rpc_model.PostTransactionRequest{
22+
// TransactionBytes: []byte{ // keep this to test multiple transaction in single block.
23+
// 1, 0, 1, 82, 108, 58, 93, 0, 0, 0, 0, 0, 0, 66, 67, 90, 110, 83, 102, 113, 112, 80, 53, 116, 113, 70, 81, 108, 77, 84, 89,
24+
// 107, 68, 101, 66, 86, 70, 87, 110, 98, 121, 86, 75, 55, 118, 76, 114, 53, 79, 82, 70, 112, 84, 106, 103, 116, 78, 0, 0, 66,
25+
// 67, 90, 75, 76, 118, 103, 85, 89, 90, 49, 75, 75, 120, 45, 106, 116, 70, 57, 75, 111, 74, 115, 107, 106, 86, 80, 118, 66, 57,
26+
// 106, 112, 73, 106, 102, 122, 122, 73, 54, 122, 68, 87, 48, 74, 1, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 16, 39, 0, 0, 0, 0, 0, 0, 140,
27+
// 134, 217, 86, 232, 251, 81, 174, 86, 44, 221, 44, 226, 73, 245, 19, 170, 94, 47, 160, 53, 20, 225, 192, 19, 200, 196, 217, 96, 64,
28+
// 66, 6, 146, 16, 61, 104, 106, 112, 122, 96, 233, 224, 208, 119, 245, 148, 60, 9, 131, 211, 110, 68, 167, 115, 243, 251, 90, 64, 234,
29+
// 66, 108, 30, 116, 9,
30+
// },
31+
TransactionBytes: []byte{
32+
1, 0, 1, 53, 119, 58, 93, 0, 0, 0, 0, 0, 0, 66, 67, 90, 110, 83, 102, 113, 112, 80, 53, 116, 113, 70, 81, 108, 77, 84, 89, 107, 68,
33+
101, 66, 86, 70, 87, 110, 98, 121, 86, 75, 55, 118, 76, 114, 53, 79, 82, 70, 112, 84, 106, 103, 116, 78, 0, 0, 66, 67, 90, 75, 76,
34+
118, 103, 85, 89, 90, 49, 75, 75, 120, 45, 106, 116, 70, 57, 75, 111, 74, 115, 107, 106, 86, 80, 118, 66, 57, 106, 112, 73, 106,
35+
102, 122, 122, 73, 54, 122, 68, 87, 48, 74, 1, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 16, 39, 0, 0, 0, 0, 0, 0, 32, 85, 34, 198, 89, 78,
36+
166, 142, 59, 148, 243, 133, 69, 66, 123, 219, 2, 3, 229, 172, 221, 35, 185, 208, 43, 44, 172, 96, 166, 116, 205, 93, 78, 194, 153,
37+
95, 243, 145, 108, 96, 42, 6, 186, 128, 59, 117, 83, 196, 26, 9, 15, 157, 215, 108, 180, 35, 195, 100, 7, 142, 47, 96, 108, 10,
38+
},
39+
})
40+
41+
if err != nil {
42+
log.Fatalf("error calling rpc_service.PostTransaction: %s", err)
43+
}
44+
45+
log.Printf("response from remote rpc_service.PostTransaction(): %s", response)
46+
47+
}

api/handler/transactionHandler.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,16 @@ func (th *TransactionHandler) GetTransactions(ctx context.Context,
3939

4040
return response, nil
4141
}
42+
43+
// PostTransaction handle transaction submitted by client
44+
func (th *TransactionHandler) PostTransaction(ctx context.Context,
45+
req *model.PostTransactionRequest) (*model.PostTransactionResponse, error) {
46+
chainType := chaintype.GetChainType(0)
47+
transaction, err := th.Service.PostTransaction(chainType, req)
48+
if err != nil {
49+
return nil, err
50+
}
51+
return &model.PostTransactionResponse{
52+
Transaction: transaction,
53+
}, nil
54+
}

api/service/transactionApiService.go

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,16 @@ package service
33
import (
44
"database/sql"
55
"errors"
6-
"fmt"
6+
"time"
7+
8+
"github.com/sirupsen/logrus"
9+
10+
"github.com/zoobc/zoobc-core/common/transaction"
11+
"github.com/zoobc/zoobc-core/core/service"
12+
13+
"github.com/zoobc/zoobc-core/common/crypto"
14+
15+
"github.com/zoobc/zoobc-core/common/util"
716

817
"github.com/zoobc/zoobc-core/common/contract"
918
"github.com/zoobc/zoobc-core/common/model"
@@ -15,20 +24,33 @@ type (
1524
TransactionServiceInterface interface {
1625
GetTransaction(contract.ChainType, *model.GetTransactionRequest) (*model.Transaction, error)
1726
GetTransactions(contract.ChainType, *model.GetTransactionsRequest) (*model.GetTransactionsResponse, error)
27+
PostTransaction(contract.ChainType, *model.PostTransactionRequest) (*model.Transaction, error)
1828
}
1929

2030
// TransactionService represents struct of TransactionService
2131
TransactionService struct {
22-
Query *query.Executor
32+
Query query.ExecutorInterface
33+
Signature crypto.SignatureInterface
34+
ActionTypeSwitcher transaction.TypeActionSwitcher
35+
MempoolService service.MempoolServiceInterface
36+
Log *logrus.Logger
2337
}
2438
)
2539

2640
var transactionServiceInstance *TransactionService
2741

2842
// NewTransactionService creates a singleton instance of TransactionService
29-
func NewTransactionService(queryExecutor *query.Executor) *TransactionService {
43+
func NewTransactionService(queryExecutor query.ExecutorInterface, signature crypto.SignatureInterface,
44+
txTypeSwitcher transaction.TypeActionSwitcher, mempoolService service.MempoolServiceInterface,
45+
log *logrus.Logger) *TransactionService {
3046
if transactionServiceInstance == nil {
31-
transactionServiceInstance = &TransactionService{Query: queryExecutor}
47+
transactionServiceInstance = &TransactionService{
48+
Query: queryExecutor,
49+
Signature: signature,
50+
ActionTypeSwitcher: txTypeSwitcher,
51+
MempoolService: mempoolService,
52+
Log: log,
53+
}
3254
}
3355
return transactionServiceInstance
3456
}
@@ -44,7 +66,6 @@ func (ts *TransactionService) GetTransaction(chainType contract.ChainType,
4466
txQuery := query.NewTransactionQuery(chainType)
4567
rows, err = ts.Query.ExecuteSelect(txQuery.GetTransaction(params.ID))
4668
if err != nil {
47-
fmt.Printf("GetTransaction fails %v\n", err)
4869
return nil, err
4970
}
5071
defer rows.Close()
@@ -70,15 +91,13 @@ func (ts *TransactionService) GetTransactions(chainType contract.ChainType,
7091
selectQuery := txQuery.GetTransactions(params.Limit, params.Offset)
7192
rows, err = ts.Query.ExecuteSelect(selectQuery)
7293
if err != nil {
73-
fmt.Printf("GetTransactions fails %v\n", err)
7494
return nil, err
7595
}
7696
defer rows.Close()
7797
txs = txQuery.BuildModel(txs, rows)
7898

7999
rows2, err = ts.Query.ExecuteSelect(query.GetTotalRecordOfSelect(selectQuery))
80100
if err != nil {
81-
fmt.Printf("GetTransactions total records fails %v\n", err)
82101
return nil, err
83102
}
84103
defer rows2.Close()
@@ -100,3 +119,61 @@ func (ts *TransactionService) GetTransactions(chainType contract.ChainType,
100119
Transactions: txs,
101120
}, nil
102121
}
122+
123+
func (ts *TransactionService) PostTransaction(chaintype contract.ChainType, req *model.PostTransactionRequest) (*model.Transaction,
124+
error) {
125+
txBytes := req.TransactionBytes
126+
// get unsigned bytes
127+
tx, err := util.ParseTransactionBytes(txBytes, true)
128+
if err != nil {
129+
return nil, err
130+
}
131+
// Validate Tx
132+
txType := ts.ActionTypeSwitcher.GetTransactionType(tx)
133+
134+
// Save to mempool
135+
mpTx := &model.MempoolTransaction{
136+
FeePerByte: 0,
137+
ID: tx.ID,
138+
TransactionBytes: txBytes,
139+
ArrivalTimestamp: time.Now().Unix(),
140+
}
141+
if err := ts.MempoolService.ValidateMempoolTransaction(mpTx); err != nil {
142+
ts.Log.Warnf("Invalid transaction submitted: %v", err)
143+
return nil, err
144+
}
145+
// Apply Unconfirmed
146+
err = ts.Query.BeginTx()
147+
if err != nil {
148+
ts.Log.Warnf("error opening db transaction %v", err)
149+
return nil, err
150+
}
151+
err = txType.ApplyUnconfirmed()
152+
if err != nil {
153+
ts.Log.Warnf("fail ApplyUnconfirmed tx: %v", err)
154+
errRollback := ts.Query.RollbackTx()
155+
if errRollback != nil {
156+
ts.Log.Warnf("error rolling back db transaction %v", errRollback)
157+
return nil, errRollback
158+
}
159+
return nil, err
160+
}
161+
err = ts.MempoolService.AddMempoolTransaction(mpTx)
162+
if err != nil {
163+
ts.Log.Warnf("error AddMempoolTransaction: %v", err)
164+
errRollback := ts.Query.RollbackTx()
165+
if errRollback != nil {
166+
ts.Log.Warnf("error rolling back db transaction %v", errRollback)
167+
return nil, err
168+
}
169+
return nil, err
170+
}
171+
err = ts.Query.CommitTx()
172+
if err != nil {
173+
ts.Log.Warnf("error committing db transaction: %v", err)
174+
return nil, err
175+
}
176+
177+
// return parsed transaction
178+
return tx, nil
179+
}

0 commit comments

Comments
 (0)