From 4355e1a09fc671b81e69f39674c551e32a39f524 Mon Sep 17 00:00:00 2001
From: Androlo <andreas@erisindustries.com>
Date: Mon, 19 Oct 2015 19:59:18 +0200
Subject: [PATCH] send tx

---
 erisdb/methods.go         | 30 +++++++++++++
 erisdb/params.go          |  7 ++++
 erisdb/pipe/pipe.go       |  3 ++
 erisdb/pipe/transactor.go | 88 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 128 insertions(+)

diff --git a/erisdb/methods.go b/erisdb/methods.go
index 7a27628d..0609f69e 100644
--- a/erisdb/methods.go
+++ b/erisdb/methods.go
@@ -42,6 +42,8 @@ const (
 	SIGN_TX                   = SERVICE_NAME + ".signTx"
 	TRANSACT                  = SERVICE_NAME + ".transact"
 	TRANSACT_AND_HOLD         = SERVICE_NAME + ".transactAndHold"
+	SEND                  	  = SERVICE_NAME + ".send"
+	SEND_AND_HOLD             = SERVICE_NAME + ".sendAndHold"
 	TRANSACT_NAMEREG          = SERVICE_NAME + ".transactNameReg"
 	EVENT_SUBSCRIBE           = SERVICE_NAME + ".eventSubscribe" // Events
 	EVENT_UNSUBSCRIBE         = SERVICE_NAME + ".eventUnsubscribe"
@@ -96,6 +98,8 @@ func (this *ErisDbMethods) getMethods() map[string]RequestHandlerFunc {
 	dhMap[SIGN_TX] = this.SignTx
 	dhMap[TRANSACT] = this.Transact
 	dhMap[TRANSACT_AND_HOLD] = this.TransactAndHold
+	dhMap[SEND] = this.Send
+	dhMap[SEND_AND_HOLD] = this.SendAndHold
 	dhMap[TRANSACT_NAMEREG] = this.TransactNameReg
 	// Namereg
 	dhMap[GET_NAMEREG_ENTRY] = this.NameRegEntry
@@ -415,6 +419,32 @@ func (this *ErisDbMethods) TransactAndHold(request *rpc.RPCRequest, requester in
 	return ce, 0, nil
 }
 
+func (this *ErisDbMethods) Send(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) {
+	param := &SendParam{}
+	err := this.codec.DecodeBytes(param, request.Params)
+	if err != nil {
+		return nil, rpc.INVALID_PARAMS, err
+	}
+	receipt, errC := this.pipe.Transactor().Send(param.PrivKey, param.ToAddress, param.Amount)
+	if errC != nil {
+		return nil, rpc.INTERNAL_ERROR, errC
+	}
+	return receipt, 0, nil
+}
+
+func (this *ErisDbMethods) SendAndHold(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) {
+	param := &SendParam{}
+	err := this.codec.DecodeBytes(param, request.Params)
+	if err != nil {
+		return nil, rpc.INVALID_PARAMS, err
+	}
+	rec, errC := this.pipe.Transactor().SendAndHold(param.PrivKey, param.ToAddress, param.Amount)
+	if errC != nil {
+		return nil, rpc.INTERNAL_ERROR, errC
+	}
+	return rec, 0, nil
+}
+
 func (this *ErisDbMethods) TransactNameReg(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) {
 	param := &TransactNameRegParam{}
 	err := this.codec.DecodeBytes(param, request.Params)
diff --git a/erisdb/params.go b/erisdb/params.go
index eb1db8d8..20467565 100644
--- a/erisdb/params.go
+++ b/erisdb/params.go
@@ -90,6 +90,13 @@ type (
 		GasLimit int64  `json:"gas_limit"`
 	}
 
+	// Used when sending a 'Send' transaction.
+	SendParam struct {
+		PrivKey   []byte `json:"priv_key"`
+		ToAddress []byte `json:"to_address"`
+		Amount    int64  `json:"amount"`
+	}
+
 	NameRegEntryParam struct {
 		Name string `json:"name"`
 	}
diff --git a/erisdb/pipe/pipe.go b/erisdb/pipe/pipe.go
index aad6a45f..6bfa2ff4 100644
--- a/erisdb/pipe/pipe.go
+++ b/erisdb/pipe/pipe.go
@@ -69,6 +69,8 @@ type (
 		Call(fromAddress, toAddress, data []byte) (*Call, error)
 		CallCode(fromAddress, code, data []byte) (*Call, error)
 		BroadcastTx(tx types.Tx) (*Receipt, error)
+		Send(privKey, toAddress []byte, amount int64) (*Receipt, error)
+		SendAndHold(privKey, toAddress []byte, amount int64) (*Receipt, error)
 		Transact(privKey, address, data []byte, gasLimit, fee int64) (*Receipt, error)
 		TransactAndHold(privKey, address, data []byte, gasLimit, fee int64) (*types.EventMsgCall, error)
 		TransactNameReg(privKey []byte, name, data string, amount, fee int64) (*Receipt, error)
@@ -98,6 +100,7 @@ func NewPipe(tNode *node.Node) Pipe {
 	namereg := newNamereg(tNode.ConsensusState())
 	net := newNetwork(tNode.Switch())
 	txs := newTransactor(tNode.EventSwitch(), tNode.ConsensusState(), tNode.MempoolReactor(), events)
+	
 	return &PipeImpl{
 		tNode,
 		accounts,
diff --git a/erisdb/pipe/transactor.go b/erisdb/pipe/transactor.go
index 7da656e4..006e07fb 100644
--- a/erisdb/pipe/transactor.go
+++ b/erisdb/pipe/transactor.go
@@ -209,6 +209,94 @@ func (this *transactor) TransactAndHold(privKey, address, data []byte, gasLimit,
 	return ret, rErr
 }
 
+func (this *transactor) Send(privKey, toAddress []byte, amount int64) (*Receipt, error) {
+	var toAddr []byte
+	if len(toAddress) == 0 {
+		toAddr = nil
+	} else if len(toAddress) != 20 {
+		return nil, fmt.Errorf("To-address is not of the right length: %d\n", len(toAddress))
+	} else {
+		toAddr = toAddress
+	}
+	
+	if len(privKey) != 64 {
+		return nil, fmt.Errorf("Private key is not of the right length: %d\n", len(privKey))
+	}
+	
+	pk := &[64]byte{}
+	copy(pk[:], privKey)
+	this.txMtx.Lock()
+	defer this.txMtx.Unlock()
+	pa := account.GenPrivAccountFromPrivKeyBytes(pk)
+	cache := this.mempoolReactor.Mempool.GetCache()
+	acc := cache.GetAccount(pa.Address)
+	var sequence int
+	if acc == nil {
+		sequence = 1
+	} else {
+		sequence = acc.Sequence + 1
+	}
+	
+	tx := types.NewSendTx()
+	
+	txInput := &types.TxInput{
+		Address:  pa.Address,
+		Amount:   amount,
+		Sequence: sequence,
+		PubKey:   pa.PubKey,
+	}
+	
+	tx.Inputs = append(tx.Inputs, txInput)
+	
+	txOutput := &types.TxOutput{toAddr, amount}
+	
+	tx.Outputs = append(tx.Outputs, txOutput);
+	
+	// Got ourselves a tx.
+	txS, errS := this.SignTx(tx, []*account.PrivAccount{pa})
+	if errS != nil {
+		return nil, errS
+	}
+	return this.BroadcastTx(txS)
+}
+
+func (this *transactor) SendAndHold(privKey, toAddress []byte, amount int64) (*Receipt, error) {
+	rec, tErr := this.Send(privKey, toAddress, amount)
+	if tErr != nil {
+		return nil, tErr
+	}
+	
+	wc := make(chan *types.SendTx)
+	subId := fmt.Sprintf("%X", rec.TxHash)
+	
+	this.eventEmitter.Subscribe(subId, types.EventStringAccOutput(toAddress), func(evt interface{}) {
+		event := evt.(*types.SendTx)
+		wc <- event
+	})
+
+	timer := time.NewTimer(300 * time.Second)
+	toChan := timer.C
+
+	var rErr error
+
+	// FOR NOW
+	pk := &[64]byte{}
+	copy(pk[:], privKey)
+	pa := account.GenPrivAccountFromPrivKeyBytes(pk)
+
+	select {
+	case <-toChan:
+		rErr = fmt.Errorf("Transaction timed out. Hash: " + subId)
+	case e := <-wc:
+		if bytes.Equal(e.Inputs[0].Address, pa.Address) && e.Inputs[0].Amount == amount {
+			timer.Stop()
+			this.eventEmitter.Unsubscribe(subId)
+			return rec, rErr
+		}
+	}
+	return nil, rErr
+}
+
 func (this *transactor) TransactNameReg(privKey []byte, name, data string, amount, fee int64) (*Receipt, error) {
 
 	if len(privKey) != 64 {
-- 
GitLab