diff --git a/erisdb/methods.go b/erisdb/methods.go index 7a27628da3939ec2b4edb1ae0102017fa8c006b4..0609f69ead0322e3f19762fea210a0296808c12c 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 eb1db8d808a03015a8c9e68ba38283eff964c356..2046756577d4ff3a0527180be8569f168d905b5f 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 aad6a45fd1e37627f9bb6cfec4110482c1e1ea8d..6bfa2ff437b91ca4f205bef09d6f085ed6eea07e 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 7da656e478b63d60a24189415128fcec687f14fe..006e07fb114b64054423eda58846e05bea73bcfe 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 {