From 12c54f95f10bcaee2194785c158dc6ef6001189c Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 11 Sep 2018 15:43:24 -0300 Subject: [PATCH 01/38] [documents] added document notarize call --- documents/call.go | 121 ++++++++++ documents/notary_contract.go | 444 +++++++++++++++++++++++++++++++++++ documents/storage.go | 9 +- 3 files changed, 571 insertions(+), 3 deletions(-) create mode 100644 documents/notary_contract.go diff --git a/documents/call.go b/documents/call.go index 392ff14..62a070a 100644 --- a/documents/call.go +++ b/documents/call.go @@ -1,9 +1,16 @@ package documents import ( + "bytes" "encoding/base64" + "encoding/json" "errors" + "net/http" "time" + + keyManager "github.com/Bit-Nation/panthalassa/keyManager" + "github.com/ethereum/go-ethereum/common" + cid "github.com/ipfs/go-cid" ) type DocumentCreateCall struct { @@ -97,6 +104,9 @@ func (c *DocumentAllCall) Handle(data map[string]interface{}) (map[string]interf "mime_type": d.MimeType, "description": d.Description, "title": d.Title, + "hash": d.Hash, + "signature": d.Signature, + "status": d.Status, }) } return map[string]interface{}{ @@ -183,3 +193,114 @@ func (d *DocumentDeleteCall) Handle(data map[string]interface{}) (map[string]int return map[string]interface{}{}, d.s.db.DeleteStruct(&doc) } + +type DocumentSubmitCall struct { + s *Storage + km *keyManager.KeyManager + n *NotaryMulti + notaryAddr common.Address +} + +func NewDocumentSubmitCall(s *Storage, km *keyManager.KeyManager, n *NotaryMulti, notaryAddr common.Address) *DocumentSubmitCall { + return &DocumentSubmitCall{ + s: s, + km: km, + n: n, + notaryAddr: notaryAddr, + } +} + +func (d *DocumentSubmitCall) CallID() string { + return "DOCUMENT:NOTARISE" +} + +func (d *DocumentSubmitCall) Validate(map[string]interface{}) error { + return nil +} + +func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]interface{}, error) { + + docID, k := data["doc_id"].(float64) + if !k { + return map[string]interface{}{}, errors.New("expect doc_id to be an integer") + } + + var doc Document + if err := d.s.db.One("ID", int(docID), &doc); err != nil { + return map[string]interface{}{}, err + } + + // prepare request data + reqData := map[string][]byte{ + "file": doc.Content, + } + rawReqData, err := json.Marshal(reqData) + if err != nil { + return map[string]interface{}{}, err + } + + // upload to ipfs + req, err := http.NewRequest("POST", "https://ipfs.infura.io:5001", bytes.NewBuffer(rawReqData)) + if err != nil { + return map[string]interface{}{}, err + } + + // exec request + client := http.Client{} + resp, err := client.Do(req) + if err != nil { + return map[string]interface{}{}, err + } + + // make sure we got a valid status code back + if resp.Status != "200" { + return map[string]interface{}{}, errors.New("invalid status: " + resp.Status) + } + + // read response + var rawResp []byte + if _, err := resp.Body.Read(rawResp); err != nil { + return map[string]interface{}{}, err + } + + // unmarshal response + respMap := map[string]string{} + if err := json.Unmarshal(rawResp, &respMap); err != nil { + return map[string]interface{}{}, err + } + + // make sure hash exist in response + strCid, exist := respMap["Hash"] + if !exist { + return map[string]interface{}{}, errors.New("hash doesn't exist in response") + } + + // cast string hash to CID + c, err := cid.Cast([]byte(strCid)) + if err != nil { + return map[string]interface{}{}, err + } + + // attach cid to document + doc.CID = c.Bytes() + + // sign cid + cidSignature, err := d.km.IdentitySign(c.Bytes()) + if err != nil { + return map[string]interface{}{}, err + } + + // attach signature to doc + doc.Signature = cidSignature + + // submit tx to chain + tx, err := d.n.NotarizeTwo(nil, d.notaryAddr, c.Bytes(), cidSignature) + if err != nil { + return map[string]interface{}{}, err + } + + doc.TransactionHash = tx.Hash().Hex() + + return map[string]interface{}{}, d.s.Save(&doc) + +} diff --git a/documents/notary_contract.go b/documents/notary_contract.go new file mode 100644 index 0000000..43c28f6 --- /dev/null +++ b/documents/notary_contract.go @@ -0,0 +1,444 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package documents + +import ( + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// NotaryABI is the input ABI used to generate the binding from. +const NotaryABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"records\",\"outputs\":[{\"name\":\"notarisedData\",\"type\":\"bytes\"},{\"name\":\"timestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_notarisedData\",\"type\":\"bytes\"}],\"name\":\"record\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"},{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_record\",\"type\":\"bytes\"}],\"name\":\"notarize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + +// NotaryBin is the compiled bytecode used for deploying new contracts. +const NotaryBin = `0x608060405234801561001057600080fd5b50610522806100206000396000f3006080604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166301e64725811461005b578063e1112648146100f2578063fb1ace341461014b575b600080fd5b34801561006757600080fd5b506100736004356101a6565b6040518080602001838152602001828103825284818151815260200191508051906020019080838360005b838110156100b657818101518382015260200161009e565b50505050905090810190601f1680156100e35780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156100fe57600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261007394369492936024939284019190819084018382808284375094975061024a9650505050505050565b34801561015757600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526101a494369492936024939284019190819084018382808284375094975061037e9650505050505050565b005b6000602081815291815260409081902080548251601f60026000196101006001861615020190931692909204918201859004850281018501909352808352909283919083018282801561023a5780601f1061020f5761010080835404028352916020019161023a565b820191906000526020600020905b81548152906001019060200180831161021d57829003601f168201915b5050505050908060010154905082565b60606000610256610443565b600080856040518082805190602001908083835b602083106102895780518252601f19909201916020918201910161026a565b518151600019602094850361010090810a8201928316921993909316919091179092526040805196909401869003909520885287820198909852958101600020815181546060601f60026001841615909802909b019091169590950498890188900490970287018401825290860187815295969095879550935085929091508401828280156103595780601f1061032e57610100808354040283529160200191610359565b820191906000526020600020905b81548152906001019060200180831161033c57829003601f168201915b5050509183525050600191909101546020918201528151910151909590945092505050565b6000816040518082805190602001908083835b602083106103b05780518252601f199092019160209182019101610391565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181529182905292902060010154919450501591506103fa905057600080fd5b604080518082018252838152426020808301919091526000848152808252929092208151805192939192610431928492019061045b565b50602082015181600101559050505050565b60408051808201909152606081526000602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061049c57805160ff19168380011785556104c9565b828001600101855582156104c9579182015b828111156104c95782518255916020019190600101906104ae565b506104d59291506104d9565b5090565b6104f391905b808211156104d557600081556001016104df565b905600a165627a7a72305820b7df842df5393139052e21c871c46429425f1394048c184e0e0e7b58843ea51b0029` + +// DeployNotary deploys a new Ethereum contract, binding an instance of Notary to it. +func DeployNotary(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Notary, error) { + parsed, err := abi.JSON(strings.NewReader(NotaryABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(NotaryBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Notary{NotaryCaller: NotaryCaller{contract: contract}, NotaryTransactor: NotaryTransactor{contract: contract}, NotaryFilterer: NotaryFilterer{contract: contract}}, nil +} + +// Notary is an auto generated Go binding around an Ethereum contract. +type Notary struct { + NotaryCaller // Read-only binding to the contract + NotaryTransactor // Write-only binding to the contract + NotaryFilterer // Log filterer for contract events +} + +// NotaryCaller is an auto generated read-only Go binding around an Ethereum contract. +type NotaryCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NotaryTransactor is an auto generated write-only Go binding around an Ethereum contract. +type NotaryTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NotaryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type NotaryFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NotarySession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type NotarySession struct { + Contract *Notary // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// NotaryCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type NotaryCallerSession struct { + Contract *NotaryCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// NotaryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type NotaryTransactorSession struct { + Contract *NotaryTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// NotaryRaw is an auto generated low-level Go binding around an Ethereum contract. +type NotaryRaw struct { + Contract *Notary // Generic contract binding to access the raw methods on +} + +// NotaryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type NotaryCallerRaw struct { + Contract *NotaryCaller // Generic read-only contract binding to access the raw methods on +} + +// NotaryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type NotaryTransactorRaw struct { + Contract *NotaryTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewNotary creates a new instance of Notary, bound to a specific deployed contract. +func NewNotary(address common.Address, backend bind.ContractBackend) (*Notary, error) { + contract, err := bindNotary(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Notary{NotaryCaller: NotaryCaller{contract: contract}, NotaryTransactor: NotaryTransactor{contract: contract}, NotaryFilterer: NotaryFilterer{contract: contract}}, nil +} + +// NewNotaryCaller creates a new read-only instance of Notary, bound to a specific deployed contract. +func NewNotaryCaller(address common.Address, caller bind.ContractCaller) (*NotaryCaller, error) { + contract, err := bindNotary(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &NotaryCaller{contract: contract}, nil +} + +// NewNotaryTransactor creates a new write-only instance of Notary, bound to a specific deployed contract. +func NewNotaryTransactor(address common.Address, transactor bind.ContractTransactor) (*NotaryTransactor, error) { + contract, err := bindNotary(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &NotaryTransactor{contract: contract}, nil +} + +// NewNotaryFilterer creates a new log filterer instance of Notary, bound to a specific deployed contract. +func NewNotaryFilterer(address common.Address, filterer bind.ContractFilterer) (*NotaryFilterer, error) { + contract, err := bindNotary(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &NotaryFilterer{contract: contract}, nil +} + +// bindNotary binds a generic wrapper to an already deployed contract. +func bindNotary(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(NotaryABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Notary *NotaryRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _Notary.Contract.NotaryCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Notary *NotaryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Notary.Contract.NotaryTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Notary *NotaryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Notary.Contract.NotaryTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Notary *NotaryCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _Notary.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Notary *NotaryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Notary.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Notary *NotaryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Notary.Contract.contract.Transact(opts, method, params...) +} + +// Record is a free data retrieval call binding the contract method 0xe1112648. +// +// Solidity: function record(_notarisedData bytes) constant returns(bytes, uint256) +func (_Notary *NotaryCaller) Record(opts *bind.CallOpts, _notarisedData []byte) ([]byte, *big.Int, error) { + var ( + ret0 = new([]byte) + ret1 = new(*big.Int) + ) + out := &[]interface{}{ + ret0, + ret1, + } + err := _Notary.contract.Call(opts, out, "record", _notarisedData) + return *ret0, *ret1, err +} + +// Record is a free data retrieval call binding the contract method 0xe1112648. +// +// Solidity: function record(_notarisedData bytes) constant returns(bytes, uint256) +func (_Notary *NotarySession) Record(_notarisedData []byte) ([]byte, *big.Int, error) { + return _Notary.Contract.Record(&_Notary.CallOpts, _notarisedData) +} + +// Record is a free data retrieval call binding the contract method 0xe1112648. +// +// Solidity: function record(_notarisedData bytes) constant returns(bytes, uint256) +func (_Notary *NotaryCallerSession) Record(_notarisedData []byte) ([]byte, *big.Int, error) { + return _Notary.Contract.Record(&_Notary.CallOpts, _notarisedData) +} + +// Records is a free data retrieval call binding the contract method 0x01e64725. +// +// Solidity: function records( bytes32) constant returns(notarisedData bytes, timestamp uint256) +func (_Notary *NotaryCaller) Records(opts *bind.CallOpts, arg0 [32]byte) (struct { + NotarisedData []byte + Timestamp *big.Int +}, error) { + ret := new(struct { + NotarisedData []byte + Timestamp *big.Int + }) + out := ret + err := _Notary.contract.Call(opts, out, "records", arg0) + return *ret, err +} + +// Records is a free data retrieval call binding the contract method 0x01e64725. +// +// Solidity: function records( bytes32) constant returns(notarisedData bytes, timestamp uint256) +func (_Notary *NotarySession) Records(arg0 [32]byte) (struct { + NotarisedData []byte + Timestamp *big.Int +}, error) { + return _Notary.Contract.Records(&_Notary.CallOpts, arg0) +} + +// Records is a free data retrieval call binding the contract method 0x01e64725. +// +// Solidity: function records( bytes32) constant returns(notarisedData bytes, timestamp uint256) +func (_Notary *NotaryCallerSession) Records(arg0 [32]byte) (struct { + NotarisedData []byte + Timestamp *big.Int +}, error) { + return _Notary.Contract.Records(&_Notary.CallOpts, arg0) +} + +// Notarize is a paid mutator transaction binding the contract method 0xfb1ace34. +// +// Solidity: function notarize(_record bytes) returns() +func (_Notary *NotaryTransactor) Notarize(opts *bind.TransactOpts, _record []byte) (*types.Transaction, error) { + return _Notary.contract.Transact(opts, "notarize", _record) +} + +// Notarize is a paid mutator transaction binding the contract method 0xfb1ace34. +// +// Solidity: function notarize(_record bytes) returns() +func (_Notary *NotarySession) Notarize(_record []byte) (*types.Transaction, error) { + return _Notary.Contract.Notarize(&_Notary.TransactOpts, _record) +} + +// Notarize is a paid mutator transaction binding the contract method 0xfb1ace34. +// +// Solidity: function notarize(_record bytes) returns() +func (_Notary *NotaryTransactorSession) Notarize(_record []byte) (*types.Transaction, error) { + return _Notary.Contract.Notarize(&_Notary.TransactOpts, _record) +} + +// NotaryMultiABI is the input ABI used to generate the binding from. +const NotaryMultiABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_notaryAddress\",\"type\":\"address\"},{\"name\":\"_firstRecord\",\"type\":\"bytes\"},{\"name\":\"_secondRecord\",\"type\":\"bytes\"}],\"name\":\"notarizeTwo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" + +// NotaryMultiBin is the compiled bytecode used for deploying new contracts. +const NotaryMultiBin = `0x608060405234801561001057600080fd5b506102fb806100206000396000f3006080604052600436106100405763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416636ca484d78114610045575b600080fd5b34801561005157600080fd5b5060408051602060046024803582810135601f81018590048502860185019096528585526100f795833573ffffffffffffffffffffffffffffffffffffffff1695369560449491939091019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a9998810197919650918201945092508291508401838280828437509497506100f99650505050505050565b005b6040517ffb1ace34000000000000000000000000000000000000000000000000000000008152602060048201818152845160248401528451869373ffffffffffffffffffffffffffffffffffffffff85169363fb1ace34938893909283926044909101919085019080838360005b8381101561017f578181015183820152602001610167565b50505050905090810190601f1680156101ac5780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b1580156101cb57600080fd5b505af11580156101df573d6000803e3d6000fd5b50506040517ffb1ace3400000000000000000000000000000000000000000000000000000000815260206004820181815286516024840152865173ffffffffffffffffffffffffffffffffffffffff8716955063fb1ace349450879391928392604401919085019080838360005b8381101561026557818101518382015260200161024d565b50505050905090810190601f1680156102925780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b1580156102b157600080fd5b505af11580156102c5573d6000803e3d6000fd5b50505050505050505600a165627a7a723058209ccebce4442a22d9a140fb00f0dd8f77d860725161bd44fae7bc44697f557b250029` + +// DeployNotaryMulti deploys a new Ethereum contract, binding an instance of NotaryMulti to it. +func DeployNotaryMulti(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *NotaryMulti, error) { + parsed, err := abi.JSON(strings.NewReader(NotaryMultiABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(NotaryMultiBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &NotaryMulti{NotaryMultiCaller: NotaryMultiCaller{contract: contract}, NotaryMultiTransactor: NotaryMultiTransactor{contract: contract}, NotaryMultiFilterer: NotaryMultiFilterer{contract: contract}}, nil +} + +// NotaryMulti is an auto generated Go binding around an Ethereum contract. +type NotaryMulti struct { + NotaryMultiCaller // Read-only binding to the contract + NotaryMultiTransactor // Write-only binding to the contract + NotaryMultiFilterer // Log filterer for contract events +} + +// NotaryMultiCaller is an auto generated read-only Go binding around an Ethereum contract. +type NotaryMultiCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NotaryMultiTransactor is an auto generated write-only Go binding around an Ethereum contract. +type NotaryMultiTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NotaryMultiFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type NotaryMultiFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NotaryMultiSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type NotaryMultiSession struct { + Contract *NotaryMulti // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// NotaryMultiCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type NotaryMultiCallerSession struct { + Contract *NotaryMultiCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// NotaryMultiTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type NotaryMultiTransactorSession struct { + Contract *NotaryMultiTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// NotaryMultiRaw is an auto generated low-level Go binding around an Ethereum contract. +type NotaryMultiRaw struct { + Contract *NotaryMulti // Generic contract binding to access the raw methods on +} + +// NotaryMultiCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type NotaryMultiCallerRaw struct { + Contract *NotaryMultiCaller // Generic read-only contract binding to access the raw methods on +} + +// NotaryMultiTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type NotaryMultiTransactorRaw struct { + Contract *NotaryMultiTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewNotaryMulti creates a new instance of NotaryMulti, bound to a specific deployed contract. +func NewNotaryMulti(address common.Address, backend bind.ContractBackend) (*NotaryMulti, error) { + contract, err := bindNotaryMulti(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &NotaryMulti{NotaryMultiCaller: NotaryMultiCaller{contract: contract}, NotaryMultiTransactor: NotaryMultiTransactor{contract: contract}, NotaryMultiFilterer: NotaryMultiFilterer{contract: contract}}, nil +} + +// NewNotaryMultiCaller creates a new read-only instance of NotaryMulti, bound to a specific deployed contract. +func NewNotaryMultiCaller(address common.Address, caller bind.ContractCaller) (*NotaryMultiCaller, error) { + contract, err := bindNotaryMulti(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &NotaryMultiCaller{contract: contract}, nil +} + +// NewNotaryMultiTransactor creates a new write-only instance of NotaryMulti, bound to a specific deployed contract. +func NewNotaryMultiTransactor(address common.Address, transactor bind.ContractTransactor) (*NotaryMultiTransactor, error) { + contract, err := bindNotaryMulti(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &NotaryMultiTransactor{contract: contract}, nil +} + +// NewNotaryMultiFilterer creates a new log filterer instance of NotaryMulti, bound to a specific deployed contract. +func NewNotaryMultiFilterer(address common.Address, filterer bind.ContractFilterer) (*NotaryMultiFilterer, error) { + contract, err := bindNotaryMulti(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &NotaryMultiFilterer{contract: contract}, nil +} + +// bindNotaryMulti binds a generic wrapper to an already deployed contract. +func bindNotaryMulti(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(NotaryMultiABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_NotaryMulti *NotaryMultiRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _NotaryMulti.Contract.NotaryMultiCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_NotaryMulti *NotaryMultiRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _NotaryMulti.Contract.NotaryMultiTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_NotaryMulti *NotaryMultiRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _NotaryMulti.Contract.NotaryMultiTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_NotaryMulti *NotaryMultiCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _NotaryMulti.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_NotaryMulti *NotaryMultiTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _NotaryMulti.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_NotaryMulti *NotaryMultiTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _NotaryMulti.Contract.contract.Transact(opts, method, params...) +} + +// NotarizeTwo is a paid mutator transaction binding the contract method 0x6ca484d7. +// +// Solidity: function notarizeTwo(_notaryAddress address, _firstRecord bytes, _secondRecord bytes) returns() +func (_NotaryMulti *NotaryMultiTransactor) NotarizeTwo(opts *bind.TransactOpts, _notaryAddress common.Address, _firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { + return _NotaryMulti.contract.Transact(opts, "notarizeTwo", _notaryAddress, _firstRecord, _secondRecord) +} + +// NotarizeTwo is a paid mutator transaction binding the contract method 0x6ca484d7. +// +// Solidity: function notarizeTwo(_notaryAddress address, _firstRecord bytes, _secondRecord bytes) returns() +func (_NotaryMulti *NotaryMultiSession) NotarizeTwo(_notaryAddress common.Address, _firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { + return _NotaryMulti.Contract.NotarizeTwo(&_NotaryMulti.TransactOpts, _notaryAddress, _firstRecord, _secondRecord) +} + +// NotarizeTwo is a paid mutator transaction binding the contract method 0x6ca484d7. +// +// Solidity: function notarizeTwo(_notaryAddress address, _firstRecord bytes, _secondRecord bytes) returns() +func (_NotaryMulti *NotaryMultiTransactorSession) NotarizeTwo(_notaryAddress common.Address, _firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { + return _NotaryMulti.Contract.NotarizeTwo(&_NotaryMulti.TransactOpts, _notaryAddress, _firstRecord, _secondRecord) +} diff --git a/documents/storage.go b/documents/storage.go index 408bb12..51d0462 100644 --- a/documents/storage.go +++ b/documents/storage.go @@ -1,9 +1,9 @@ package documents import ( - "github.com/Bit-Nation/panthalassa/crypto/aes" - "github.com/Bit-Nation/panthalassa/keyManager" - "github.com/asdine/storm" + aes "github.com/Bit-Nation/panthalassa/crypto/aes" + keyManager "github.com/Bit-Nation/panthalassa/keyManager" + storm "github.com/asdine/storm" ) type Document struct { @@ -14,6 +14,9 @@ type Document struct { Content []byte `json:"-"` EncryptedContent aes.CipherText CreatedAt int64 + CID []byte + Signature []byte + TransactionHash string } type Storage struct { From bbc8cf9f1308e7cf3a80109857dc7f3935758a34 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 11 Sep 2018 16:37:04 -0300 Subject: [PATCH 02/38] [docs] added notarise command --- documents/call.go | 6 +++--- mobile_interface.go | 42 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/documents/call.go b/documents/call.go index 62a070a..080a0eb 100644 --- a/documents/call.go +++ b/documents/call.go @@ -104,9 +104,9 @@ func (c *DocumentAllCall) Handle(data map[string]interface{}) (map[string]interf "mime_type": d.MimeType, "description": d.Description, "title": d.Title, - "hash": d.Hash, + "hash": d.CID, "signature": d.Signature, - "status": d.Status, + "tx_hash": d.TransactionHash, }) } return map[string]interface{}{ @@ -201,7 +201,7 @@ type DocumentSubmitCall struct { notaryAddr common.Address } -func NewDocumentSubmitCall(s *Storage, km *keyManager.KeyManager, n *NotaryMulti, notaryAddr common.Address) *DocumentSubmitCall { +func NewDocumentNotariseCall(s *Storage, km *keyManager.KeyManager, n *NotaryMulti, notaryAddr common.Address) *DocumentSubmitCall { return &DocumentSubmitCall{ s: s, km: km, diff --git a/mobile_interface.go b/mobile_interface.go index 2a57279..583be76 100644 --- a/mobile_interface.go +++ b/mobile_interface.go @@ -1,6 +1,7 @@ package panthalassa import ( + "context" "encoding/base64" "encoding/hex" "encoding/json" @@ -24,6 +25,8 @@ import ( uiapi "github.com/Bit-Nation/panthalassa/uiapi" "github.com/asdine/storm" bolt "github.com/coreos/bbolt" + common "github.com/ethereum/go-ethereum/common" + ethclient "github.com/ethereum/go-ethereum/ethclient" proto "github.com/golang/protobuf/proto" log "github.com/ipfs/go-log" ma "github.com/multiformats/go-multiaddr" @@ -139,10 +142,44 @@ func start(dbDir string, km *keyManager.KeyManager, config StartConfig, client, // dyncall registry dcr := dyncall.New() - if err := RegisterDocumentCalls(dcr, dbInstance, km); err != nil { + // register document related calls + docStorage := documents.NewStorage(dbInstance, km) + if err := RegisterDocumentCalls(dcr, docStorage, km); err != nil { + return err + } + + ethClient, err := ethclient.Dial(config.EthWsEndpoint) + if err != nil { + return err + } + + var notaryMulti common.Address + var notary common.Address + + networkID, err := ethClient.NetworkID(context.Background()) + if err != nil { return err } + // make sure network is correct + if networkID.Int64() != int64(4) { + return errors.New("there is only a notary for the rinkeby testnet") + } + + // rinkeby addresses + notary = common.HexToAddress("0xd75afa5c92cefded2862d2770f6a0929af74067d") + notaryMulti = common.HexToAddress("0x00d238247ae4324f952d2c9a297dd5f76ed0e7c0") + + notaryContract, err := documents.NewNotaryMulti(notaryMulti, ethClient) + if err != nil { + return err + } + notariseCall := documents.NewDocumentNotariseCall(docStorage, km, notaryContract, notary) + if err := dcr.Register(notariseCall); err != nil { + return err + } + + // register contract calls if err := RegisterContactCalls(dcr, dbInstance); err != nil { return err } @@ -163,8 +200,7 @@ func start(dbDir string, km *keyManager.KeyManager, config StartConfig, client, return nil } -func RegisterDocumentCalls(dcr *dyncall.Registry, dbInstance *storm.DB, km *keyManager.KeyManager) error { - docStorage := documents.NewStorage(dbInstance, km) +func RegisterDocumentCalls(dcr *dyncall.Registry, docStorage *documents.Storage, km *keyManager.KeyManager) error { // register document all call allCall := documents.NewDocumentAllCall(docStorage) From 2993dad28975760545afd050cabc841ccb12da11 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Thu, 13 Sep 2018 17:45:45 -0300 Subject: [PATCH 03/38] [eth] fix --- Gopkg.lock | 163 ++++++++++++++++++++++++++++++++++++++------ Gopkg.toml | 2 +- db/bolt_to_storm.go | 14 ++-- db/migration.go | 2 +- mobile_interface.go | 4 +- 5 files changed, 153 insertions(+), 32 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 4fbce4f..1513661 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -35,6 +35,25 @@ ] revision = "5312a61534124124185d41f09206b9fef1d88403" +[[projects]] + branch = "master" + name = "github.com/aristanetworks/goarista" + packages = ["monotime"] + revision = "ff33da284e760fcdb03c33d37a719e5ed30ba844" + +[[projects]] + name = "github.com/asdine/storm" + packages = [ + ".", + "codec", + "codec/json", + "index", + "internal", + "q" + ] + revision = "5a6fe65e3993f63951c8e3f64c812536c9e23595" + version = "v2.1.2" + [[projects]] branch = "master" name = "github.com/btcsuite/btcd" @@ -59,19 +78,41 @@ revision = "346938d642f2ec3594ed81d874461961cd0faa76" version = "v1.1.0" +[[projects]] + name = "github.com/deckarep/golang-set" + packages = ["."] + revision = "1d4478f51bed434f1dadf96dcd9b43aabac66795" + version = "v1.7" + [[projects]] name = "github.com/ethereum/go-ethereum" packages = [ + ".", + "accounts", + "accounts/abi", + "accounts/abi/bind", + "accounts/keystore", "common", "common/hexutil", "common/math", + "common/mclock", + "core/types", "crypto", "crypto/secp256k1", "crypto/sha3", - "rlp" + "ethclient", + "ethdb", + "event", + "log", + "metrics", + "p2p/netutil", + "params", + "rlp", + "rpc", + "trie" ] - revision = "37685930d953bcbe023f9bc65b135a8d8b8f1488" - version = "v1.8.12" + revision = "89451f7c382ad2185987ee369f16416f89c28a7d" + version = "v1.8.15" [[projects]] name = "github.com/fd/go-nat" @@ -79,6 +120,12 @@ revision = "bad65a492f32121a87197f4a085905c35e2a367e" version = "v1.0.0" +[[projects]] + name = "github.com/go-stack/stack" + packages = ["."] + revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a" + version = "v1.8.0" + [[projects]] name = "github.com/gogo/protobuf" packages = [ @@ -94,6 +141,18 @@ revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" version = "v1.1.0" +[[projects]] + branch = "master" + name = "github.com/golang/snappy" + packages = ["."] + revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" + +[[projects]] + name = "github.com/google/uuid" + packages = ["."] + revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" + version = "v1.0.0" + [[projects]] name = "github.com/gorilla/context" packages = ["."] @@ -155,6 +214,12 @@ ] revision = "75cbd19cc9af4467702602311230785df263b671" +[[projects]] + name = "github.com/iris-contrib/go.uuid" + packages = ["."] + revision = "36e9d2ebbde5e3f13ab2e25625fd453271d6522e" + version = "v2.0.0" + [[projects]] name = "github.com/jackpal/gateway" packages = ["."] @@ -190,6 +255,12 @@ ] revision = "b497e2f366b8624394fb2e89c10ab607bebdde0b" +[[projects]] + name = "github.com/kataras/iris" + packages = ["core/errors"] + revision = "217d9feadc0fc5b317826a901065e0c4c27d3cad" + version = "10.7.0" + [[projects]] name = "github.com/libp2p/go-addr-util" packages = ["."] @@ -468,6 +539,12 @@ revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38" version = "v1.0.2" +[[projects]] + name = "github.com/pborman/uuid" + packages = ["."] + revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1" + version = "v1.2" + [[projects]] name = "github.com/pmezard/go-difflib" packages = ["difflib"] @@ -475,17 +552,16 @@ version = "v1.0.0" [[projects]] - name = "github.com/robertkrimen/otto" - packages = [ - ".", - "ast", - "dbg", - "file", - "parser", - "registry", - "token" - ] - revision = "15f95af6e78dcd2030d8195a138bd88d4f403546" + name = "github.com/rjeczalik/notify" + packages = ["."] + revision = "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8" + version = "v0.9.1" + +[[projects]] + name = "github.com/rs/cors" + packages = ["."] + revision = "3fb1b69b103a84de38a19c3c6ec073dd6caa4d3f" + version = "v1.5.0" [[projects]] name = "github.com/satori/go.uuid" @@ -502,6 +578,25 @@ revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" version = "v1.2.2" +[[projects]] + branch = "master" + name = "github.com/syndtr/goleveldb" + packages = [ + "leveldb", + "leveldb/cache", + "leveldb/comparer", + "leveldb/errors", + "leveldb/filter", + "leveldb/iterator", + "leveldb/journal", + "leveldb/memdb", + "leveldb/opt", + "leveldb/storage", + "leveldb/table", + "leveldb/util" + ] + revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd" + [[projects]] name = "github.com/tiabc/doubleratchet" packages = ["."] @@ -577,6 +672,12 @@ packages = ["."] revision = "cb29a700b01dc3c2fdd743c00cf54685056bb62a" +[[projects]] + name = "go.etcd.io/bbolt" + packages = ["."] + revision = "583e8937c61f1af6513608ccc75c97b6abdf4ff9" + version = "v1.3.0" + [[projects]] branch = "master" name = "golang.org/x/crypto" @@ -600,7 +701,8 @@ "context", "html", "html/atom", - "html/charset" + "html/charset", + "websocket" ] revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0" @@ -638,17 +740,36 @@ version = "v0.3.0" [[projects]] - name = "gopkg.in/sourcemap.v1" + branch = "master" + name = "golang.org/x/tools" packages = [ - ".", - "base64vlq" + "go/ast/astutil", + "imports", + "internal/fastwalk" ] - revision = "6e83acea0053641eff084973fee085f0c193c61a" - version = "v1.0.5" + revision = "677d2ff680c188ddb7dcd2bfa6bc7d3f2f2f75b2" + +[[projects]] + branch = "v2" + name = "gopkg.in/karalabe/cookiejar.v2" + packages = ["collections/prque"] + revision = "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57" + +[[projects]] + branch = "v2" + name = "gopkg.in/natefinch/npipe.v2" + packages = ["."] + revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6" + +[[projects]] + branch = "v3" + name = "gopkg.in/olebedev/go-duktape.v3" + packages = ["."] + revision = "d53328019b21fe1987c97f368f98c072c8f44455" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "74990307dbe7b3f0288ac0bdaa0a720a17eb375c2486a238482be0e36d92bb57" + inputs-digest = "298a8ade8ec5b9208e922a5f62e91e7b5151af951b74f5781adc62455395a574" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index dfcb186..b7d565a 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -34,7 +34,7 @@ [[constraint]] name = "github.com/ethereum/go-ethereum" - version = "1.8.11" + version = "1.8.15" [[constraint]] branch = "master" diff --git a/db/bolt_to_storm.go b/db/bolt_to_storm.go index 31c695b..b712184 100644 --- a/db/bolt_to_storm.go +++ b/db/bolt_to_storm.go @@ -6,13 +6,13 @@ import ( "errors" "time" - aes "github.com/Bit-Nation/panthalassa/crypto/aes" - keyManager "github.com/Bit-Nation/panthalassa/keyManager" - queue "github.com/Bit-Nation/panthalassa/queue" - x3dh "github.com/Bit-Nation/x3dh" - storm "github.com/asdine/storm" - bolt "github.com/coreos/bbolt" + "github.com/Bit-Nation/panthalassa/crypto/aes" + "github.com/Bit-Nation/panthalassa/keyManager" + "github.com/Bit-Nation/panthalassa/queue" + "github.com/Bit-Nation/x3dh" + "github.com/asdine/storm" dr "github.com/tiabc/doubleratchet" + bolt "go.etcd.io/bbolt" ) type BoltToStormMigration struct { @@ -20,7 +20,7 @@ type BoltToStormMigration struct { } func (m *BoltToStormMigration) Migrate(db *storm.DB) error { - + // migrate queue jobs err := db.Bolt.Update(func(tx *bolt.Tx) error { queueStorage := queue.NewStorage(db.WithTransaction(tx)) diff --git a/db/migration.go b/db/migration.go index 935a4f9..364f367 100644 --- a/db/migration.go +++ b/db/migration.go @@ -13,7 +13,7 @@ import ( "time" storm "github.com/asdine/storm" - bolt "github.com/coreos/bbolt" + bolt "go.etcd.io/bbolt" ) type Migration interface { diff --git a/mobile_interface.go b/mobile_interface.go index 583be76..a8fcbb3 100644 --- a/mobile_interface.go +++ b/mobile_interface.go @@ -23,13 +23,13 @@ import ( profile "github.com/Bit-Nation/panthalassa/profile" queue "github.com/Bit-Nation/panthalassa/queue" uiapi "github.com/Bit-Nation/panthalassa/uiapi" - "github.com/asdine/storm" - bolt "github.com/coreos/bbolt" + storm "github.com/asdine/storm" common "github.com/ethereum/go-ethereum/common" ethclient "github.com/ethereum/go-ethereum/ethclient" proto "github.com/golang/protobuf/proto" log "github.com/ipfs/go-log" ma "github.com/multiformats/go-multiaddr" + bolt "go.etcd.io/bbolt" ) var panthalassaInstance *Panthalassa From 13cd42d96d060f3553274f8c23b03008836b5dcb Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Mon, 17 Sep 2018 00:17:35 -0300 Subject: [PATCH 04/38] [deps] updated protobuf --- Gopkg.lock | 60 ++++++++++++++++++++++++++++----------------- Gopkg.toml | 2 +- mobile_interface.go | 2 +- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 4fbce4f..2872730 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -4,8 +4,7 @@ [[projects]] name = "github.com/Bit-Nation/protobuffers" packages = ["."] - revision = "b60cd16e6d11da8b88a4f1732fc916e3458952a4" - version = "1.1.0" + revision = "a71cefee1ec2dda6f720cacaa1b3217b1589e33c" [[projects]] branch = "master" @@ -35,6 +34,19 @@ ] revision = "5312a61534124124185d41f09206b9fef1d88403" +[[projects]] + name = "github.com/asdine/storm" + packages = [ + ".", + "codec", + "codec/json", + "index", + "internal", + "q" + ] + revision = "5a6fe65e3993f63951c8e3f64c812536c9e23595" + version = "v2.1.2" + [[projects]] branch = "master" name = "github.com/btcsuite/btcd" @@ -155,6 +167,12 @@ ] revision = "75cbd19cc9af4467702602311230785df263b671" +[[projects]] + name = "github.com/iris-contrib/go.uuid" + packages = ["."] + revision = "36e9d2ebbde5e3f13ab2e25625fd453271d6522e" + version = "v2.0.0" + [[projects]] name = "github.com/jackpal/gateway" packages = ["."] @@ -190,6 +208,12 @@ ] revision = "b497e2f366b8624394fb2e89c10ab607bebdde0b" +[[projects]] + name = "github.com/kataras/iris" + packages = ["core/errors"] + revision = "217d9feadc0fc5b317826a901065e0c4c27d3cad" + version = "10.7.0" + [[projects]] name = "github.com/libp2p/go-addr-util" packages = ["."] @@ -474,19 +498,6 @@ revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" -[[projects]] - name = "github.com/robertkrimen/otto" - packages = [ - ".", - "ast", - "dbg", - "file", - "parser", - "registry", - "token" - ] - revision = "15f95af6e78dcd2030d8195a138bd88d4f403546" - [[projects]] name = "github.com/satori/go.uuid" packages = ["."] @@ -577,6 +588,12 @@ packages = ["."] revision = "cb29a700b01dc3c2fdd743c00cf54685056bb62a" +[[projects]] + name = "go.etcd.io/bbolt" + packages = ["."] + revision = "583e8937c61f1af6513608ccc75c97b6abdf4ff9" + version = "v1.3.0" + [[projects]] branch = "master" name = "golang.org/x/crypto" @@ -638,17 +655,14 @@ version = "v0.3.0" [[projects]] - name = "gopkg.in/sourcemap.v1" - packages = [ - ".", - "base64vlq" - ] - revision = "6e83acea0053641eff084973fee085f0c193c61a" - version = "v1.0.5" + branch = "v3" + name = "gopkg.in/olebedev/go-duktape.v3" + packages = ["."] + revision = "d53328019b21fe1987c97f368f98c072c8f44455" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "74990307dbe7b3f0288ac0bdaa0a720a17eb375c2486a238482be0e36d92bb57" + inputs-digest = "470d40dd4b96cf5aca7d1710b5dcf5bea1be9e20be5860b8530a9824997a99b9" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index dfcb186..6dee435 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -138,4 +138,4 @@ [[constraint]] name = "github.com/Bit-Nation/protobuffers" - version = "1.1.0" + revision = "a71cefee1ec2dda6f720cacaa1b3217b1589e33c" diff --git a/mobile_interface.go b/mobile_interface.go index 2a57279..dc5b607 100644 --- a/mobile_interface.go +++ b/mobile_interface.go @@ -22,7 +22,7 @@ import ( profile "github.com/Bit-Nation/panthalassa/profile" queue "github.com/Bit-Nation/panthalassa/queue" uiapi "github.com/Bit-Nation/panthalassa/uiapi" - "github.com/asdine/storm" + storm "github.com/asdine/storm" bolt "github.com/coreos/bbolt" proto "github.com/golang/protobuf/proto" log "github.com/ipfs/go-log" From acaefbf157ab900ee6d5c00d217bbba5a30ab216 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 18 Sep 2018 15:13:29 -0300 Subject: [PATCH 05/38] [docs] ipfs fix attempt --- documents/call.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documents/call.go b/documents/call.go index 080a0eb..e4d0b28 100644 --- a/documents/call.go +++ b/documents/call.go @@ -240,7 +240,8 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int } // upload to ipfs - req, err := http.NewRequest("POST", "https://ipfs.infura.io:5001", bytes.NewBuffer(rawReqData)) + req, err := http.NewRequest("POST", "https://ipfs.infura.io:5001/api/v0/add", bytes.NewBuffer(rawReqData)) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") if err != nil { return map[string]interface{}{}, err } From 007ac654119e8f33d0a4de978ccc6059284df167 Mon Sep 17 00:00:00 2001 From: Andrii Selivanov Date: Tue, 18 Sep 2018 21:27:44 +0300 Subject: [PATCH 06/38] [docs] Added more logs for notarise call error. --- documents/call.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/documents/call.go b/documents/call.go index e4d0b28..1756b65 100644 --- a/documents/call.go +++ b/documents/call.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "encoding/json" "errors" + "io/ioutil" "net/http" "time" @@ -255,7 +256,8 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int // make sure we got a valid status code back if resp.Status != "200" { - return map[string]interface{}{}, errors.New("invalid status: " + resp.Status) + b, _ := ioutil.ReadAll(resp.Body) + return map[string]interface{}{}, errors.New("invalid status: " + resp.Status + ", body: " + string(b)) } // read response From 6d6ae2e5dfea9fb62e5c7b67e2a3287378d424e1 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 18 Sep 2018 15:55:52 -0300 Subject: [PATCH 07/38] [docs] removed ipfs --- documents/call.go | 68 ++++++++++------------------------------------- 1 file changed, 14 insertions(+), 54 deletions(-) diff --git a/documents/call.go b/documents/call.go index e4d0b28..827b6c0 100644 --- a/documents/call.go +++ b/documents/call.go @@ -1,16 +1,16 @@ package documents import ( - "bytes" "encoding/base64" - "encoding/json" "errors" - "net/http" "time" keyManager "github.com/Bit-Nation/panthalassa/keyManager" - "github.com/ethereum/go-ethereum/common" + bind "github.com/ethereum/go-ethereum/accounts/abi/bind" + common "github.com/ethereum/go-ethereum/common" + types "github.com/ethereum/go-ethereum/core/types" cid "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" ) type DocumentCreateCall struct { @@ -230,63 +230,19 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int return map[string]interface{}{}, err } - // prepare request data - reqData := map[string][]byte{ - "file": doc.Content, - } - rawReqData, err := json.Marshal(reqData) - if err != nil { - return map[string]interface{}{}, err - } - - // upload to ipfs - req, err := http.NewRequest("POST", "https://ipfs.infura.io:5001/api/v0/add", bytes.NewBuffer(rawReqData)) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + // hash document + docHash, err := mh.Sum(doc.Content, mh.SHA2_256, -1) if err != nil { return map[string]interface{}{}, err } - // exec request - client := http.Client{} - resp, err := client.Do(req) - if err != nil { - return map[string]interface{}{}, err - } - - // make sure we got a valid status code back - if resp.Status != "200" { - return map[string]interface{}{}, errors.New("invalid status: " + resp.Status) - } - - // read response - var rawResp []byte - if _, err := resp.Body.Read(rawResp); err != nil { - return map[string]interface{}{}, err - } - - // unmarshal response - respMap := map[string]string{} - if err := json.Unmarshal(rawResp, &respMap); err != nil { - return map[string]interface{}{}, err - } - - // make sure hash exist in response - strCid, exist := respMap["Hash"] - if !exist { - return map[string]interface{}{}, errors.New("hash doesn't exist in response") - } - - // cast string hash to CID - c, err := cid.Cast([]byte(strCid)) - if err != nil { - return map[string]interface{}{}, err - } + docContentCID := cid.NewCidV1(cid.Raw, docHash).Bytes() // attach cid to document - doc.CID = c.Bytes() + doc.CID = docContentCID // sign cid - cidSignature, err := d.km.IdentitySign(c.Bytes()) + cidSignature, err := d.km.IdentitySign(docContentCID) if err != nil { return map[string]interface{}{}, err } @@ -295,7 +251,11 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int doc.Signature = cidSignature // submit tx to chain - tx, err := d.n.NotarizeTwo(nil, d.notaryAddr, c.Bytes(), cidSignature) + tx, err := d.n.NotarizeTwo(&bind.TransactOpts{ + Signer: func(signer types.Signer, addresses common.Address, transaction *types.Transaction) (*types.Transaction, error) { + return transaction, nil + }, + }, d.notaryAddr, docContentCID, cidSignature) if err != nil { return map[string]interface{}{}, err } From bbba09653bbbfaf52572c72ecd89cd806a5c7286 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 18 Sep 2018 19:05:11 -0300 Subject: [PATCH 08/38] [tests] fixed tests --- chat/chat.go | 2 +- chat/group_chat.go | 4 ++-- chat/queue_processor.go | 2 +- chat/receive_message.go | 4 ++-- chat/save_message_test.go | 11 +++++++++-- chat/send_and_receive_func_test.go | 17 +++++++++++------ dapp/module/message/message.go | 2 +- dapp/module/message/message_test.go | 2 +- db/bolt_to_storm.go | 4 ++-- db/chat_storage.go | 24 ++++++++++++++++++++++-- db/chat_storage_test.go | 2 +- db/migration_test.go | 2 +- 12 files changed, 54 insertions(+), 22 deletions(-) diff --git a/chat/chat.go b/chat/chat.go index 216bc97..0221be7 100644 --- a/chat/chat.go +++ b/chat/chat.go @@ -46,7 +46,7 @@ func (c *Chat) AllChats() ([]db.Chat, error) { } func (c *Chat) Messages(partner ed25519.PublicKey, start int64, amount uint) ([]*db.Message, error) { - chat, err := c.chatStorage.GetChat(partner) + chat, err := c.chatStorage.GetChatByPartner(partner) if err != nil { return nil, err } diff --git a/chat/group_chat.go b/chat/group_chat.go index 460704d..8ecf1ba 100644 --- a/chat/group_chat.go +++ b/chat/group_chat.go @@ -36,7 +36,7 @@ func (c *Chat) AddUserToGroupChat(partners []ed25519.PublicKey, chatID int) erro return err } if partnerChat == nil { - if _, err := c.chatStorage.CreateChat(partner); err != nil { + if err := c.chatStorage.CreateChat(partner); err != nil { return err } } @@ -90,7 +90,7 @@ func (c *Chat) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { return 0, err } if partnerChat == nil { - if _, err := c.chatStorage.CreateChat(partner); err != nil { + if err := c.chatStorage.CreateChat(partner); err != nil { return 0, err } } diff --git a/chat/queue_processor.go b/chat/queue_processor.go index 715f130..9691955 100644 --- a/chat/queue_processor.go +++ b/chat/queue_processor.go @@ -98,7 +98,7 @@ func (p *SubmitMessagesProcessor) Process(j queue.Job) error { return err } - chat, err := p.chatDB.GetChat(partner) + chat, err := p.chatDB.GetChatByPartner(partner) if err != nil { return err } diff --git a/chat/receive_message.go b/chat/receive_message.go index 223ac0f..fd47c86 100644 --- a/chat/receive_message.go +++ b/chat/receive_message.go @@ -117,7 +117,7 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { logger.Debugf("double ratchet message %s", drMessage) // make sure chat exist - chat, err := c.chatStorage.GetChat(msg.Sender) + chat, err := c.chatStorage.GetChatByPartner(msg.Sender) if err != nil { return err } @@ -126,7 +126,7 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { return err } } - chat, err = c.chatStorage.GetChat(msg.Sender) + chat, err = c.chatStorage.GetChatByPartner(msg.Sender) if err != nil { return err } diff --git a/chat/save_message_test.go b/chat/save_message_test.go index 67fc35b..6f6fd09 100644 --- a/chat/save_message_test.go +++ b/chat/save_message_test.go @@ -16,11 +16,18 @@ func TestChat_SavePrivateMessage(t *testing.T) { km := createKeyManager() + chatStorage := db.NewChatStorage(createStorm(), []func(e db.MessagePersistedEvent){}, km) + c := Chat{ - chatStorage: db.NewChatStorage(createStorm(), []func(e db.MessagePersistedEvent){}, km), + chatStorage: chatStorage, km: km, } - require.Nil(t, c.SavePrivateMessage(pub, []byte("hi"))) + require.Nil(t, chatStorage.CreateChat(pub)) + + chat, err := chatStorage.GetChatByPartner(pub) + require.Nil(t, err) + + require.Nil(t, c.SaveMessage(chat.ID, []byte("hi"))) } diff --git a/chat/send_and_receive_func_test.go b/chat/send_and_receive_func_test.go index 6627297..3029687 100644 --- a/chat/send_and_receive_func_test.go +++ b/chat/send_and_receive_func_test.go @@ -2,7 +2,6 @@ package chat import ( "encoding/hex" - "fmt" "testing" "time" @@ -180,8 +179,6 @@ func TestChatBetweenAliceAndBob(t *testing.T) { continue } - fmt.Println(msg) - } // alice case msg := <-aliceTrans.sendChan: @@ -241,7 +238,12 @@ func TestChatBetweenAliceAndBob(t *testing.T) { require.Nil(t, err) // persist private message for bob - require.Nil(t, alice.SavePrivateMessage(bobIDKey, []byte("hi bob"))) + require.Nil(t, alice.chatStorage.CreateChat(bobIDKey)) + bobChat, err := alice.chatStorage.GetChatByPartner(bobIDKey) + require.Nil(t, err) + require.NotNil(t, bobChat) + + require.Nil(t, alice.SaveMessage(bobChat.ID, []byte("hi bob"))) // done signal done := make(chan struct{}, 1) @@ -267,7 +269,6 @@ func TestChatBetweenAliceAndBob(t *testing.T) { // make sure shared secret got accepted shSec, err := alice.sharedSecStorage.GetYoungest(bobIDKey) - fmt.Println(shSec.ID) require.Nil(t, err) require.NotNil(t, shSec) require.True(t, shSec.Accepted) @@ -295,7 +296,11 @@ func TestChatBetweenAliceAndBob(t *testing.T) { require.Equal(t, hex.EncodeToString(aliceIDKey), hex.EncodeToString(shSec.Partner)) require.True(t, shSec.Accepted) - err = bob.SavePrivateMessage(aliceIDKey, []byte("hi alice")) + // fetch chat + chat, err := bob.chatStorage.GetChatByPartner(aliceIDKey) + require.Nil(t, err) + + err = bob.SaveMessage(chat.ID, []byte("hi alice")) require.Nil(t, err) } diff --git a/dapp/module/message/message.go b/dapp/module/message/message.go index f88f1b7..ea41f8b 100644 --- a/dapp/module/message/message.go +++ b/dapp/module/message/message.go @@ -147,7 +147,7 @@ func (m *Module) Register(vm *duktape.Context) error { dec <- struct{}{} }() - chat, err := m.chatStorage.GetChat(chat) + chat, err := m.chatStorage.GetChatByPartner(chat) if err != nil { handleError(err.Error()) return diff --git a/dapp/module/message/message_test.go b/dapp/module/message/message_test.go index bdbd6c5..e67a301 100644 --- a/dapp/module/message/message_test.go +++ b/dapp/module/message/message_test.go @@ -65,7 +65,7 @@ func TestPersistMessageSuccessfully(t *testing.T) { // storage mock chatStorage := db.NewChatStorage(createStorm(), []func(e db.MessagePersistedEvent){}, createKeyManager()) chatStorage.AddListener(func(e db.MessagePersistedEvent) { - chat, _ := chatStorage.GetChat(chatPubKey) + chat, _ := chatStorage.GetChatByPartner(chatPubKey) if err != nil { panic(err) } diff --git a/db/bolt_to_storm.go b/db/bolt_to_storm.go index b712184..1e01f72 100644 --- a/db/bolt_to_storm.go +++ b/db/bolt_to_storm.go @@ -20,7 +20,7 @@ type BoltToStormMigration struct { } func (m *BoltToStormMigration) Migrate(db *storm.DB) error { - + // migrate queue jobs err := db.Bolt.Update(func(tx *bolt.Tx) error { queueStorage := queue.NewStorage(db.WithTransaction(tx)) @@ -293,7 +293,7 @@ func (m *BoltToStormMigration) Migrate(db *storm.DB) error { return err } - chat, err := chatDB.GetChat(partner) + chat, err := chatDB.GetChatByPartner(partner) if err != nil { return err } diff --git a/db/chat_storage.go b/db/chat_storage.go index f29050a..29eba2b 100644 --- a/db/chat_storage.go +++ b/db/chat_storage.go @@ -256,7 +256,7 @@ type ChatStorage interface { GetChatByPartner(pubKey ed25519.PublicKey) (*Chat, error) GetChat(chatID int) (*Chat, error) // returned int is the chat ID - CreateChat(partner ed25519.PublicKey) (int, error) + CreateChat(partner ed25519.PublicKey) error CreateGroupChat(partners []ed25519.PublicKey) (int, error) AddListener(func(e MessagePersistedEvent)) AllChats() ([]Chat, error) @@ -277,7 +277,27 @@ type BoltChatStorage struct { km *km.KeyManager } -func (s *BoltChatStorage) GetChat(partner ed25519.PublicKey) (*Chat, error) { +func (s *BoltChatStorage) GetChat(chatID int) (*Chat, error) { + + amountChats, err := s.db.Count(&Chat{}) + if err != nil { + return nil, err + } + + if amountChats == 0 { + return nil, nil + } + + chat := &Chat{} + chat.km = s.km + chat.db = s.db + chat.postPersistListener = s.postPersistListener + + return chat, s.db.One("ID", amountChats, chat) + +} + +func (s *BoltChatStorage) GetChatByPartner(partner ed25519.PublicKey) (*Chat, error) { // check if partner chat exist q := s.db.Select(sq.Eq("Partner", partner)) diff --git a/db/chat_storage_test.go b/db/chat_storage_test.go index e3a1366..7c994b0 100644 --- a/db/chat_storage_test.go +++ b/db/chat_storage_test.go @@ -98,7 +98,7 @@ func TestChatMessages(t *testing.T) { // create chat require.Nil(t, chatStor.CreateChat(partner)) - chat, err := chatStor.GetChat(partner) + chat, err := chatStor.GetChatByPartner(partner) require.Nil(t, err) require.NotNil(t, chat) diff --git a/db/migration_test.go b/db/migration_test.go index 47685b0..f6d9228 100644 --- a/db/migration_test.go +++ b/db/migration_test.go @@ -11,8 +11,8 @@ import ( "time" storm "github.com/asdine/storm" - bolt "github.com/coreos/bbolt" require "github.com/stretchr/testify/require" + bolt "go.etcd.io/bbolt" ) type migration struct { From b549b5b21d11ce532af3f257d9508ad2dcfeaeeb Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Wed, 19 Sep 2018 00:18:07 -0300 Subject: [PATCH 09/38] [chat] worked on group chat fixes --- Gopkg.toml | 2 +- chat/group_chat.go | 32 +++-- chat/receive_message.go | 59 ++++++-- chat/send_and_receive_func_test.go | 216 +++++++++++++++++++++++++++++ chat/send_message.go | 7 +- chat/utils.go | 9 +- db/chat_storage.go | 117 +++++++++++----- 7 files changed, 384 insertions(+), 58 deletions(-) diff --git a/Gopkg.toml b/Gopkg.toml index c70937f..f865205 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -138,4 +138,4 @@ [[constraint]] name = "github.com/Bit-Nation/protobuffers" - revision = "a71cefee1ec2dda6f720cacaa1b3217b1589e33c" + revision = "33c86defae2223c6141c48825b0f9960d7cb5265" diff --git a/chat/group_chat.go b/chat/group_chat.go index 8ecf1ba..4583fa7 100644 --- a/chat/group_chat.go +++ b/chat/group_chat.go @@ -3,8 +3,10 @@ package chat import ( "errors" + "encoding/hex" db "github.com/Bit-Nation/panthalassa/db" ed25519 "golang.org/x/crypto/ed25519" + "time" ) func (c *Chat) AddUserToGroupChat(partners []ed25519.PublicKey, chatID int) error { @@ -51,10 +53,8 @@ func (c *Chat) AddUserToGroupChat(partners []ed25519.PublicKey, chatID int) erro // persist message msg := db.Message{ AddUserToChat: &db.AddUserToChat{ - Users: partners, - SharedSecret: chat.GroupChatSharedSecret, - SharedSecretID: chat.GroupSharedSecretID, - ChatID: chat.GroupChatRemoteID, + Users: partners, + ChatID: chat.GroupChatRemoteID, }, } if err := partnerChat.PersistMessage(msg); err != nil { @@ -81,7 +81,18 @@ func (c *Chat) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { return 0, err } - // fetch chat + // sender + idKeyStr, err := c.km.IdentityPublicKey() + if err != nil { + return 0, err + } + + idKey, err := hex.DecodeString(idKeyStr) + if err != nil { + return 0, err + } + + // send message to our group chat partners for _, partner := range partners { // fetch chat @@ -105,11 +116,14 @@ func (c *Chat) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { // persist message msg := db.Message{ AddUserToChat: &db.AddUserToChat{ - Users: partners, - SharedSecret: groupChat.GroupChatSharedSecret, - SharedSecretID: groupChat.GroupSharedSecretID, - ChatID: groupChat.GroupChatRemoteID, + Users: partners, + ChatID: groupChat.GroupChatRemoteID, }, + Version: 1, + CreatedAt: time.Now().UnixNano(), + Status: db.StatusPersisted, + Sender: idKey, + GroupChatID: partnerChat.GroupChatRemoteID, } if err := partnerChat.PersistMessage(msg); err != nil { return 0, err diff --git a/chat/receive_message.go b/chat/receive_message.go index fd47c86..96a0fa0 100644 --- a/chat/receive_message.go +++ b/chat/receive_message.go @@ -329,18 +329,61 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { return err } - // persist message - if err := chat.PersistMessage(dbMessage); err != nil { - return err - } - // if the decryption didn't fail we want to mark // the shared secret as accepted if !sharedSec.Accepted { - fmt.Println("going to accept shared secret") - return c.sharedSecStorage.Accept(sharedSec) + if err := c.sharedSecStorage.Accept(sharedSec); err != nil { + return err + } + } + + // create group chat / add members + if dbMessage.AddUserToChat != nil { + fmt.Println("add user to chat") + // fetch group chat + groupChat, err := c.chatStorage.GetGroupChatByRemoteID(dbMessage.AddUserToChat.ChatID) + if err != nil { + return err + } + + // when the group chat doesn't exist we need to create it + if groupChat == nil { + fmt.Println("create group chat") + return c.chatStorage.CreateGroupChatFromMsg(dbMessage.AddUserToChat) + } + + // add new users + for _, newUser := range dbMessage.AddUserToChat.Users { + exist := false + for _, user := range groupChat.Partners { + if hex.EncodeToString(user) == hex.EncodeToString(newUser) { + exist = true + } + } + if exist == true { + groupChat.Partners = append(groupChat.Partners, newUser) + } + } + + groupChat.GroupChatRemoteID = dbMessage.AddUserToChat.ChatID + + // @todo update group chat + + return nil + } + + // persist group chat message in the correct chat + if len(dbMessage.GroupChatID) != 0 { + groupChat, err := c.chatStorage.GetGroupChatByRemoteID(dbMessage.GroupChatID) + if err != nil { + return err + } + if groupChat == nil { + return fmt.Errorf("couldn't find group chat for id: %x", dbMessage.GroupChatID) + } + return groupChat.PersistMessage(dbMessage) } - return nil + return chat.PersistMessage(dbMessage) } diff --git a/chat/send_and_receive_func_test.go b/chat/send_and_receive_func_test.go index 3029687..476cd40 100644 --- a/chat/send_and_receive_func_test.go +++ b/chat/send_and_receive_func_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "fmt" backend "github.com/Bit-Nation/panthalassa/backend" db "github.com/Bit-Nation/panthalassa/db" profile "github.com/Bit-Nation/panthalassa/profile" @@ -12,6 +13,7 @@ import ( uiapi "github.com/Bit-Nation/panthalassa/uiapi" bpb "github.com/Bit-Nation/protobuffers" require "github.com/stretchr/testify/require" + ed25519 "golang.org/x/crypto/ed25519" ) type chatTestBackendTransport struct { @@ -310,3 +312,217 @@ func TestChatBetweenAliceAndBob(t *testing.T) { } } + +func TestGroupChatBetweenAliceAndBob(t *testing.T) { + + alice, aliceTrans, bob, bobTrans, err := createAliceAndBob() + + // listen for bob's messages + bobReceivedMsgChan := make(chan db.MessagePersistedEvent, 10) + bob.chatStorage.AddListener(func(e db.MessagePersistedEvent) { + bobReceivedMsgChan <- e + }) + bobIDKeyStr, err := bob.km.IdentityPublicKey() + require.Nil(t, err) + bobIDKey, err := hex.DecodeString(bobIDKeyStr) + require.Nil(t, err) + + // listen for alice messages + aliceReceivedMsgChan := make(chan db.MessagePersistedEvent, 10) + alice.chatStorage.AddListener(func(e db.MessagePersistedEvent) { + aliceReceivedMsgChan <- e + }) + aliceIDKeyStr, err := alice.km.IdentityPublicKey() + require.Nil(t, err) + aliceIDKey, err := hex.DecodeString(aliceIDKeyStr) + require.Nil(t, err) + + // bob go + go func() { + + bobSignedPreKey := new(bpb.PreKey) + bobSignedPreKey = nil + + aliceSignedPreKey := new(bpb.PreKey) + aliceSignedPreKey = nil + + for { + select { + case msg := <-bobTrans.sendChan: + + if msg.Request != nil { + + // handle uploaded pre key + if msg.Request.NewSignedPreKey != nil { + bobSignedPreKey = msg.Request.NewSignedPreKey + bobTrans.receiveChan <- &bpb.BackendMessage{ + RequestID: msg.RequestID, + } + continue + } + + if len(msg.Request.PreKeyBundle) != 0 { + + aliceProfile, err := profile.SignProfile("bob", "", "", *bob.km) + if err != nil { + panic(err) + } + aliceProfileProto, err := aliceProfile.ToProtobuf() + if err != nil { + panic(err) + } + + bobTrans.receiveChan <- &bpb.BackendMessage{ + RequestID: msg.RequestID, + Response: &bpb.BackendMessage_Response{ + PreKeyBundle: &bpb.BackendMessage_PreKeyBundle{ + SignedPreKey: aliceSignedPreKey, + Profile: aliceProfileProto, + }, + }, + } + continue + } + + // handle message send to bob + // (the nice thing is that we can write it from alice to bob :)) + if len(msg.Request.Messages) != 0 { + aliceTrans.receiveChan <- msg + bobTrans.receiveChan <- &bpb.BackendMessage{ + RequestID: msg.RequestID, + } + continue + } + + } + // alice + case msg := <-aliceTrans.sendChan: + + if msg.Request != nil { + // handle the pre key bundle request for bob + if len(msg.Request.PreKeyBundle) != 0 { + + bobProfile, err := profile.SignProfile("bob", "", "", *bob.km) + if err != nil { + panic(err) + } + bobProfileProto, err := bobProfile.ToProtobuf() + if err != nil { + panic(err) + } + + <-time.After(time.Second) + + aliceTrans.receiveChan <- &bpb.BackendMessage{ + RequestID: msg.RequestID, + Response: &bpb.BackendMessage_Response{ + PreKeyBundle: &bpb.BackendMessage_PreKeyBundle{ + SignedPreKey: bobSignedPreKey, + Profile: bobProfileProto, + }, + }, + } + continue + } + + // handle upload of our new pre key bundle + if msg.Request.NewSignedPreKey != nil { + aliceSignedPreKey = msg.Request.NewSignedPreKey + aliceTrans.receiveChan <- &bpb.BackendMessage{ + RequestID: msg.RequestID, + } + continue + } + + // handle message send to bob + // (the nice thing is that we can write it from alice to bob :)) + if len(msg.Request.Messages) != 0 { + bobTrans.receiveChan <- msg + aliceTrans.receiveChan <- &bpb.BackendMessage{ + RequestID: msg.RequestID, + } + continue + } + } + + } + + } + }() + + require.Nil(t, err) + + groupChatID, err := alice.CreateGroupChat([]ed25519.PublicKey{bobIDKey}) + require.Nil(t, err) + require.Nil(t, alice.SaveMessage(groupChatID, []byte("hi @all"))) + + // done signal + done := make(chan struct{}, 1) + + for { + + select { + case msgEv := <-aliceReceivedMsgChan: + + msg := msgEv.Message + + if msg.Received { + + // make sure message is as we expect it to be + require.Equal(t, "Greeting @all", string(msg.Message)) + require.Equal(t, hex.EncodeToString(bobIDKey), hex.EncodeToString(msg.Sender)) + require.Equal(t, uint(1), msg.Version) + require.Equal(t, db.StatusPersisted, msg.Status) + + // we need to wait a bit since this is called async + // before the receive handling logic has the chance to update + // the shared secret + time.Sleep(time.Second) + + // make sure shared secret got accepted + shSec, err := alice.sharedSecStorage.GetYoungest(bobIDKey) + require.Nil(t, err) + require.NotNil(t, shSec) + require.True(t, shSec.Accepted) + + done <- struct{}{} + } + + case msgEv := <-bobReceivedMsgChan: + + msg := msgEv.Message + + // handle received messages + if msg.Received { + fmt.Println(msg.GroupChatID) + if string(msg.Message) == "" { + continue + } + + // make sure the messages is as we expect it to be + require.Equal(t, "hi @all", string(msg.Message)) + require.True(t, msg.Received) + require.Equal(t, db.StatusPersisted, msg.Status) + require.Equal(t, uint(1), msg.Version) + + // make sure shared secret got persisted + shSec, err := bob.sharedSecStorage.GetYoungest(aliceIDKey) + require.Nil(t, err) + require.NotNil(t, shSec) + require.Equal(t, hex.EncodeToString(aliceIDKey), hex.EncodeToString(shSec.Partner)) + require.True(t, shSec.Accepted) + + // fetch chat + groupChat, err := bob.chatStorage.GetChatByPartner(aliceIDKey) + require.Nil(t, err) + + groupChat.SaveMessage([]byte("Greeting @all")) + + } + + case <-done: + return + } + } + +} diff --git a/chat/send_message.go b/chat/send_message.go index 790a88b..25d6f4d 100644 --- a/chat/send_message.go +++ b/chat/send_message.go @@ -30,7 +30,8 @@ func (c *Chat) SendMessage(receiver ed25519.PublicKey, dbMessage db.Message) err Message: dbMessage.Message, MessageID: dbMessage.ID, // this version is NOT the same as the version from the database message - Version: 1, + Version: 1, + GroupChatID: dbMessage.GroupChatID, } // attach add user data @@ -44,9 +45,7 @@ func (c *Chat) SendMessage(receiver ed25519.PublicKey, dbMessage db.Message) err } return users }(), - SharedSecret: addUserMsg.SharedSecret[:], - SharedSecretID: addUserMsg.SharedSecretID, - ChatID: addUserMsg.ChatID, + ChatID: addUserMsg.ChatID, } } diff --git a/chat/utils.go b/chat/utils.go index 133aa53..d867cd0 100644 --- a/chat/utils.go +++ b/chat/utils.go @@ -165,7 +165,6 @@ func hashChatMessage(msg bpb.ChatMessage) (mh.Multihash, error) { // turns a received plain protobuf message into a database message func protoPlainMsgToMessage(msg *bpb.PlainChatMessage) (db.Message, error) { - m := db.Message{ ID: msg.MessageID, Message: msg.Message, @@ -173,6 +172,14 @@ func protoPlainMsgToMessage(msg *bpb.PlainChatMessage) (db.Message, error) { Version: uint(msg.Version), } + if msg.AddUserPrivChat != nil { + m.AddUserToChat = &db.AddUserToChat{} + m.AddUserToChat.ChatID = msg.AddUserPrivChat.ChatID + for _, user := range msg.AddUserPrivChat.Users { + m.AddUserToChat.Users = append(m.AddUserToChat.Users, user) + } + } + if isDAppMessage(msg) { m.DApp = &db.DAppMessage{ DAppPublicKey: msg.DAppPublicKey, diff --git a/db/chat_storage.go b/db/chat_storage.go index 29eba2b..fe139a1 100644 --- a/db/chat_storage.go +++ b/db/chat_storage.go @@ -1,16 +1,18 @@ package db import ( + "crypto/rand" + "encoding/hex" "errors" "fmt" - "crypto/rand" - "encoding/hex" aes "github.com/Bit-Nation/panthalassa/crypto/aes" km "github.com/Bit-Nation/panthalassa/keyManager" storm "github.com/asdine/storm" sq "github.com/asdine/storm/q" + uuid "github.com/satori/go.uuid" ed25519 "golang.org/x/crypto/ed25519" + "time" ) // message status @@ -36,11 +38,6 @@ var statuses = map[Status]bool{ // validate a given message var ValidMessage = func(m Message) error { - // validate id - if m.ID == "" { - return errors.New("invalid message id (empty string)") - } - // validate version if m.Version == 0 { return errors.New("invalid version - got 0") @@ -52,7 +49,7 @@ var ValidMessage = func(m Message) error { } // validate "type" of message - if m.DApp == nil && len(m.Message) == 0 { + if m.DApp == nil && m.AddUserToChat == nil && len(m.Message) == 0 { return errors.New("got invalid message - dapp and message are both nil") } @@ -90,11 +87,8 @@ type DAppMessage struct { } type AddUserToChat struct { - Users []ed25519.PublicKey - // @todo encrypt - SharedSecret [32]byte - SharedSecretID []byte - ChatID []byte + Users []ed25519.PublicKey + ChatID []byte } type Message struct { @@ -113,26 +107,58 @@ type Message struct { UniqueMsgID int64 `storm:"index"` ChatID int `storm:"index"` AddUserToChat *AddUserToChat + GroupChatID []byte } type Chat struct { ID int `storm:"id,increment"` // partner will only be filled if this is a private chat - Partner ed25519.PublicKey `storm:"index,unique"` - Partners []ed25519.PublicKey - // @todo encrypt this - GroupChatSharedSecret [32]byte - GroupSharedSecretID []byte - UnreadMessages bool - GroupChatRemoteID []byte - db storm.Node - km *km.KeyManager - postPersistListener []func(event MessagePersistedEvent) + Partner ed25519.PublicKey `storm:"index,unique"` + Partners []ed25519.PublicKey + UnreadMessages bool + GroupChatRemoteID []byte + db storm.Node + km *km.KeyManager + postPersistListener []func(event MessagePersistedEvent) } // @todo maybe more checks func (c *Chat) IsGroupChat() bool { - return len(c.GroupSharedSecretID) != 0 + return len(c.GroupChatRemoteID) != 0 +} + +var nowAsUnix = func() int64 { + return time.Now().UnixNano() +} + +// save a raw message +func (c *Chat) SaveMessage(rawMessage []byte) error { + + id, err := uuid.NewV4() + if err != nil { + return err + } + + senderStr, err := c.km.IdentityPublicKey() + if err != nil { + return err + } + sender, err := hex.DecodeString(senderStr) + if err != nil { + return err + } + + msg := Message{ + ID: id.String(), + Message: rawMessage, + CreatedAt: nowAsUnix(), + Version: 1, + Status: StatusPersisted, + Sender: sender, + } + + // fetch chat + return c.PersistMessage(msg) } func (c *Chat) GetMessage(msgID int64) (*Message, error) { @@ -166,7 +192,7 @@ func (c *Chat) GetMessage(msgID int64) (*Message, error) { } -// Persist Message +// Persist Message struct func (c *Chat) PersistMessage(msg Message) error { msg.ChatID = c.ID ct, err := c.km.AESEncrypt(msg.Message) @@ -255,9 +281,11 @@ func (c *Chat) Messages(start int64, amount uint) ([]*Message, error) { type ChatStorage interface { GetChatByPartner(pubKey ed25519.PublicKey) (*Chat, error) GetChat(chatID int) (*Chat, error) + GetGroupChatByRemoteID(id []byte) (*Chat, error) // returned int is the chat ID CreateChat(partner ed25519.PublicKey) error CreateGroupChat(partners []ed25519.PublicKey) (int, error) + CreateGroupChatFromMsg(createMessage *AddUserToChat) error AddListener(func(e MessagePersistedEvent)) AllChats() ([]Chat, error) // set state of chat to unread messages @@ -277,6 +305,33 @@ type BoltChatStorage struct { km *km.KeyManager } +func (s *BoltChatStorage) CreateGroupChatFromMsg(createMessage *AddUserToChat) error { + + c := Chat{ + Partners: createMessage.Users, + GroupChatRemoteID: createMessage.ChatID, + } + + return s.db.Save(&c) + +} + +func (s *BoltChatStorage) GetGroupChatByRemoteID(id []byte) (*Chat, error) { + + // make sure chats exist + amount, err := s.db.Count(&Chat{}) + if err != nil { + return nil, err + } + if amount == 0 { + return nil, nil + } + + c := &Chat{} + return c, s.db.One("GroupChatRemoteID", id, c) + +} + func (s *BoltChatStorage) GetChat(chatID int) (*Chat, error) { amountChats, err := s.db.Count(&Chat{}) @@ -355,12 +410,6 @@ func (s *BoltChatStorage) AllChats() ([]Chat, error) { func (s *BoltChatStorage) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { - // generate group chat shared secret - ss := [32]byte{} - if _, err := rand.Read(ss[:]); err != nil { - return 0, err - } - // remote id ri := make([]byte, 200) if _, err := rand.Read(ri); err != nil { @@ -374,10 +423,8 @@ func (s *BoltChatStorage) CreateGroupChat(partners []ed25519.PublicKey) (int, er } c := &Chat{ - Partners: partners, - GroupChatSharedSecret: ss, - GroupChatRemoteID: ri, - GroupSharedSecretID: ssID, + Partners: partners, + GroupChatRemoteID: ri, } if err := s.db.Save(c); err != nil { From dee7277aafae86065c12f3a044a4f3a1107bf80a Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Wed, 19 Sep 2018 01:14:20 -0300 Subject: [PATCH 10/38] [chat] worked on group id for messages --- Gopkg.toml | 2 +- chat/group_chat.go | 6 +++--- chat/receive_message.go | 2 +- chat/save_message.go | 1 - chat/send_and_receive_func_test.go | 14 ++++++++++++-- db/chat_storage.go | 2 +- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Gopkg.toml b/Gopkg.toml index f865205..914b9ea 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -138,4 +138,4 @@ [[constraint]] name = "github.com/Bit-Nation/protobuffers" - revision = "33c86defae2223c6141c48825b0f9960d7cb5265" + revision = "d9946ea4c0fa569249294c8645bdca0151a17fd6" diff --git a/chat/group_chat.go b/chat/group_chat.go index 4583fa7..295cdea 100644 --- a/chat/group_chat.go +++ b/chat/group_chat.go @@ -1,12 +1,12 @@ package chat import ( + "encoding/hex" "errors" + "time" - "encoding/hex" db "github.com/Bit-Nation/panthalassa/db" ed25519 "golang.org/x/crypto/ed25519" - "time" ) func (c *Chat) AddUserToGroupChat(partners []ed25519.PublicKey, chatID int) error { @@ -123,7 +123,7 @@ func (c *Chat) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { CreatedAt: time.Now().UnixNano(), Status: db.StatusPersisted, Sender: idKey, - GroupChatID: partnerChat.GroupChatRemoteID, + GroupChatID: groupChat.GroupChatRemoteID, } if err := partnerChat.PersistMessage(msg); err != nil { return 0, err diff --git a/chat/receive_message.go b/chat/receive_message.go index 96a0fa0..600555a 100644 --- a/chat/receive_message.go +++ b/chat/receive_message.go @@ -339,7 +339,7 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { // create group chat / add members if dbMessage.AddUserToChat != nil { - fmt.Println("add user to chat") + // fetch group chat groupChat, err := c.chatStorage.GetGroupChatByRemoteID(dbMessage.AddUserToChat.ChatID) if err != nil { diff --git a/chat/save_message.go b/chat/save_message.go index 0b1a23d..adb7f70 100644 --- a/chat/save_message.go +++ b/chat/save_message.go @@ -13,7 +13,6 @@ var nowAsUnix = func() int64 { return time.Now().UnixNano() } -// persist private message func (c *Chat) SaveMessage(chatID int, rawMessage []byte) error { id, err := uuid.NewV4() if err != nil { diff --git a/chat/send_and_receive_func_test.go b/chat/send_and_receive_func_test.go index 476cd40..e96c546 100644 --- a/chat/send_and_receive_func_test.go +++ b/chat/send_and_receive_func_test.go @@ -5,7 +5,6 @@ import ( "testing" "time" - "fmt" backend "github.com/Bit-Nation/panthalassa/backend" db "github.com/Bit-Nation/panthalassa/db" profile "github.com/Bit-Nation/panthalassa/profile" @@ -459,6 +458,9 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { // done signal done := make(chan struct{}, 1) + // group chat id + var remoteGroupChatID []byte + for { select { @@ -494,11 +496,19 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { // handle received messages if msg.Received { - fmt.Println(msg.GroupChatID) + + // the first message we get should be a message to init a group chat + if msg.AddUserToChat != nil { + remoteGroupChatID = msg.AddUserToChat.ChatID + } + if string(msg.Message) == "" { continue } + // make sure group ID has been set + require.Equal(t, 200, len(remoteGroupChatID)) + // make sure the messages is as we expect it to be require.Equal(t, "hi @all", string(msg.Message)) require.True(t, msg.Received) diff --git a/db/chat_storage.go b/db/chat_storage.go index fe139a1..c53826d 100644 --- a/db/chat_storage.go +++ b/db/chat_storage.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "errors" "fmt" + "time" aes "github.com/Bit-Nation/panthalassa/crypto/aes" km "github.com/Bit-Nation/panthalassa/keyManager" @@ -12,7 +13,6 @@ import ( sq "github.com/asdine/storm/q" uuid "github.com/satori/go.uuid" ed25519 "golang.org/x/crypto/ed25519" - "time" ) // message status From c56480f1cf236a4774908b1a86d6b14297421237 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Wed, 19 Sep 2018 04:26:37 -0300 Subject: [PATCH 11/38] [chat] fixed tests --- chat/handler.go | 5 +- chat/queue_processor.go | 88 +++++++++++++----------------- chat/queue_processor_test.go | 9 +-- chat/receive_message.go | 69 ++++++++++++++++------- chat/send_and_receive_func_test.go | 28 +++------- chat/utils.go | 9 +-- db/chat_storage.go | 41 +++++++++++--- 7 files changed, 137 insertions(+), 112 deletions(-) diff --git a/chat/handler.go b/chat/handler.go index 362681f..bb06b51 100644 --- a/chat/handler.go +++ b/chat/handler.go @@ -5,9 +5,8 @@ import ( "encoding/hex" "encoding/json" "errors" - "sync" - "strconv" + "sync" preKey "github.com/Bit-Nation/panthalassa/chat/prekey" db "github.com/Bit-Nation/panthalassa/db" @@ -118,7 +117,7 @@ func (c *Chat) handlePersistedMessage(e db.MessagePersistedEvent) { err := c.queue.AddJob(queue.Job{ Type: "MESSAGE:SUBMIT", Data: map[string]interface{}{ - "partner": e.Chat.Partner, + "chat_id": e.Chat.ID, "db_message_id": e.Message.UniqueMsgID, }, }) diff --git a/chat/queue_processor.go b/chat/queue_processor.go index 9691955..574977f 100644 --- a/chat/queue_processor.go +++ b/chat/queue_processor.go @@ -1,14 +1,11 @@ package chat import ( - "encoding/base64" - "encoding/json" + "encoding/hex" "errors" - "fmt" db "github.com/Bit-Nation/panthalassa/db" queue "github.com/Bit-Nation/panthalassa/queue" - ed25519 "golang.org/x/crypto/ed25519" ) // processor that submits messages from the queue to the backend @@ -39,50 +36,21 @@ func (p *SubmitMessagesProcessor) ValidJob(j queue.Job) error { } // get data from job -func (p *SubmitMessagesProcessor) jobToData(j queue.Job) (ed25519.PublicKey, int64, error) { - // validate message id - var messageId int64 - var messageIdErr error - messageIdInterface, oki := j.Data["db_message_id"] +func (p *SubmitMessagesProcessor) jobToData(j queue.Job) (int, int64, error) { + + // fetch chatID + chatID, oki := j.Data["chat_id"].(int) if !oki { - return nil, 0, errors.New("db_message_id is missing") - } - switch msgId := messageIdInterface.(type) { - case json.Number: - messageId, messageIdErr = msgId.Int64() - if messageIdErr != nil { - return nil, 0, messageIdErr - } - case int64: - messageId = msgId - default: - return nil, 0, errors.New("Expected : json.Number/int64, Got : " + fmt.Sprint(msgId)) + return 0, 0, errors.New("expected chat id to be a float64") } - if messageId == 0 { - return nil, 0, errors.New("message id is 0") - } - // check partner - var partner []byte - var partnerErr error - partnerInterface, oki := j.Data["partner"] + + messageID, oki := j.Data["db_message_id"].(int64) if !oki { - return nil, 0, errors.New("partner is missing") + return 0, 0, errors.New("expected message id to be a float64") } - switch potentialPartner := partnerInterface.(type) { - case string: - partner, partnerErr = base64.StdEncoding.DecodeString(potentialPartner) - if partnerErr != nil { - return nil, 0, partnerErr - } - case ed25519.PublicKey: - partner = potentialPartner - default: - return nil, 0, errors.New("Expected : base64 string/ed25519.PublicKey, Got : " + fmt.Sprint(potentialPartner)) - } - if len(partner) != 32 { - return nil, 0, errors.New("invalid partner id length") - } - return partner, messageId, nil + + return int(chatID), messageID, nil + } func (p *SubmitMessagesProcessor) Process(j queue.Job) error { @@ -93,12 +61,12 @@ func (p *SubmitMessagesProcessor) Process(j queue.Job) error { } // get data from job map - partner, messageID, err := p.jobToData(j) + chatId, messageID, err := p.jobToData(j) if err != nil { return err } - chat, err := p.chatDB.GetChatByPartner(partner) + chat, err := p.chatDB.GetChat(chatId) if err != nil { return err } @@ -112,10 +80,30 @@ func (p *SubmitMessagesProcessor) Process(j queue.Job) error { return errors.New("failed to fetch message") } - // send message - err = p.chat.SendMessage(partner, *msg) - if err != nil { - return err + if chat.IsGroupChat() { + + for _, groupMember := range chat.Partners { + + // make sure we don't send to our self + idPubKey, err := p.chat.km.IdentityPublicKey() + if err != nil { + return err + } + if idPubKey == hex.EncodeToString(groupMember) { + continue + } + + msg.GroupChatID = chat.GroupChatRemoteID + if err := p.chat.SendMessage(groupMember, *msg); err != nil { + return err + } + + } + } else { + err = p.chat.SendMessage(chat.Partner, *msg) + if err != nil { + return err + } } // delete job diff --git a/chat/queue_processor_test.go b/chat/queue_processor_test.go index 16cd4a5..0a8cf3f 100644 --- a/chat/queue_processor_test.go +++ b/chat/queue_processor_test.go @@ -1,25 +1,20 @@ package chat import ( - "crypto/rand" "testing" queue "github.com/Bit-Nation/panthalassa/queue" require "github.com/stretchr/testify/require" - ed25519 "golang.org/x/crypto/ed25519" ) func TestSubmitMessagesProcessor_ValidJob(t *testing.T) { - pub, _, err := ed25519.GenerateKey(rand.Reader) - require.Nil(t, err) - p := SubmitMessagesProcessor{} - err = p.ValidJob(queue.Job{ + err := p.ValidJob(queue.Job{ Type: "MESSAGE:SUBMIT", Data: map[string]interface{}{ "db_message_id": int64(3), - "partner": pub, + "chat_id": 3, }, }) require.Nil(t, err) diff --git a/chat/receive_message.go b/chat/receive_message.go index 600555a..a38ecca 100644 --- a/chat/receive_message.go +++ b/chat/receive_message.go @@ -189,14 +189,28 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { if err != nil { return err } + // convert proto plain message to decrypted message dbMessage, err := protoPlainMsgToMessage(&decryptedMsg) + if err != nil { + return err + } dbMessage.Status = db.StatusPersisted dbMessage.Sender = sender dbMessage.Received = true - if err != nil { - return err + + // persist group chat message in the correct chat + if len(dbMessage.GroupChatID) == 200 && dbMessage.AddUserToChat == nil { + groupChat, err := c.chatStorage.GetGroupChatByRemoteID(dbMessage.GroupChatID) + if err != nil { + return err + } + if groupChat == nil { + return fmt.Errorf("couldn't find group chat for id: %x", dbMessage.GroupChatID) + } + return groupChat.PersistMessage(dbMessage) } + return chat.PersistMessage(dbMessage) } @@ -291,6 +305,36 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { return err } + if dbMessage.AddUserToChat != nil { + + // fetch group chat + groupChat, err := c.chatStorage.GetGroupChatByRemoteID(dbMessage.AddUserToChat.ChatID) + if err != nil { + return err + } + + // when the group chat doesn't exist we need to create it + if groupChat == nil { + return c.chatStorage.CreateGroupChatFromMsg(dbMessage.AddUserToChat) + } + + return nil + + } + + // persist group chat message in the correct chat + if len(dbMessage.GroupChatID) == 200 && dbMessage.AddUserToChat == nil { + + groupChat, err := c.chatStorage.GetGroupChatByRemoteID(dbMessage.GroupChatID) + if err != nil { + return err + } + if groupChat == nil { + return fmt.Errorf("couldn't find group chat for id: %x", dbMessage.GroupChatID) + } + return groupChat.PersistMessage(dbMessage) + } + return chat.PersistMessage(dbMessage) } @@ -348,32 +392,15 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { // when the group chat doesn't exist we need to create it if groupChat == nil { - fmt.Println("create group chat") return c.chatStorage.CreateGroupChatFromMsg(dbMessage.AddUserToChat) } - // add new users - for _, newUser := range dbMessage.AddUserToChat.Users { - exist := false - for _, user := range groupChat.Partners { - if hex.EncodeToString(user) == hex.EncodeToString(newUser) { - exist = true - } - } - if exist == true { - groupChat.Partners = append(groupChat.Partners, newUser) - } - } - - groupChat.GroupChatRemoteID = dbMessage.AddUserToChat.ChatID - - // @todo update group chat - return nil + } // persist group chat message in the correct chat - if len(dbMessage.GroupChatID) != 0 { + if len(dbMessage.GroupChatID) == 200 && dbMessage.AddUserToChat == nil { groupChat, err := c.chatStorage.GetGroupChatByRemoteID(dbMessage.GroupChatID) if err != nil { return err diff --git a/chat/send_and_receive_func_test.go b/chat/send_and_receive_func_test.go index e96c546..cd6476a 100644 --- a/chat/send_and_receive_func_test.go +++ b/chat/send_and_receive_func_test.go @@ -12,6 +12,8 @@ import ( uiapi "github.com/Bit-Nation/panthalassa/uiapi" bpb "github.com/Bit-Nation/protobuffers" require "github.com/stretchr/testify/require" + // log "gx/ipfs/QmTG23dvpBCBjqQwyDxV8CQT6jmS4PSftNr1VqHhE3MLy7/go-log" + "fmt" ed25519 "golang.org/x/crypto/ed25519" ) @@ -313,7 +315,7 @@ func TestChatBetweenAliceAndBob(t *testing.T) { } func TestGroupChatBetweenAliceAndBob(t *testing.T) { - + // log.SetDebugLogging() alice, aliceTrans, bob, bobTrans, err := createAliceAndBob() // listen for bob's messages @@ -458,9 +460,6 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { // done signal done := make(chan struct{}, 1) - // group chat id - var remoteGroupChatID []byte - for { select { @@ -470,6 +469,9 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { if msg.Received { + // make sure group id is ok + // require.Equal(t, hex.EncodeToString(remoteGroupChatID), hex.EncodeToString(msgEv.Chat.GroupChatRemoteID)) + fmt.Println("got message") // make sure message is as we expect it to be require.Equal(t, "Greeting @all", string(msg.Message)) require.Equal(t, hex.EncodeToString(bobIDKey), hex.EncodeToString(msg.Sender)) @@ -497,17 +499,8 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { // handle received messages if msg.Received { - // the first message we get should be a message to init a group chat - if msg.AddUserToChat != nil { - remoteGroupChatID = msg.AddUserToChat.ChatID - } - - if string(msg.Message) == "" { - continue - } - // make sure group ID has been set - require.Equal(t, 200, len(remoteGroupChatID)) + require.Equal(t, 200, len(msgEv.Chat.GroupChatRemoteID)) // make sure the messages is as we expect it to be require.Equal(t, "hi @all", string(msg.Message)) @@ -522,11 +515,8 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { require.Equal(t, hex.EncodeToString(aliceIDKey), hex.EncodeToString(shSec.Partner)) require.True(t, shSec.Accepted) - // fetch chat - groupChat, err := bob.chatStorage.GetChatByPartner(aliceIDKey) - require.Nil(t, err) - - groupChat.SaveMessage([]byte("Greeting @all")) + // send message back + require.Nil(t, msgEv.Chat.SaveMessage([]byte("Greeting @all"))) } diff --git a/chat/utils.go b/chat/utils.go index d867cd0..0ec88ec 100644 --- a/chat/utils.go +++ b/chat/utils.go @@ -166,10 +166,11 @@ func hashChatMessage(msg bpb.ChatMessage) (mh.Multihash, error) { // turns a received plain protobuf message into a database message func protoPlainMsgToMessage(msg *bpb.PlainChatMessage) (db.Message, error) { m := db.Message{ - ID: msg.MessageID, - Message: msg.Message, - CreatedAt: msg.CreatedAt, - Version: uint(msg.Version), + ID: msg.MessageID, + Message: msg.Message, + CreatedAt: msg.CreatedAt, + Version: uint(msg.Version), + GroupChatID: msg.GroupChatID, } if msg.AddUserPrivChat != nil { diff --git a/db/chat_storage.go b/db/chat_storage.go index c53826d..6095ee2 100644 --- a/db/chat_storage.go +++ b/db/chat_storage.go @@ -116,7 +116,7 @@ type Chat struct { Partner ed25519.PublicKey `storm:"index,unique"` Partners []ed25519.PublicKey UnreadMessages bool - GroupChatRemoteID []byte + GroupChatRemoteID []byte `storm:"unique"` db storm.Node km *km.KeyManager postPersistListener []func(event MessagePersistedEvent) @@ -124,7 +124,7 @@ type Chat struct { // @todo maybe more checks func (c *Chat) IsGroupChat() bool { - return len(c.GroupChatRemoteID) != 0 + return len(c.GroupChatRemoteID) == 200 } var nowAsUnix = func() int64 { @@ -307,6 +307,18 @@ type BoltChatStorage struct { func (s *BoltChatStorage) CreateGroupChatFromMsg(createMessage *AddUserToChat) error { + // add our self to the users + ourIDKeyStr, err := s.km.IdentityPublicKey() + if err != nil { + return err + } + ourIDKeyHex, err := hex.DecodeString(ourIDKeyStr) + if err != nil { + return err + } + + createMessage.Users = append(createMessage.Users, ourIDKeyHex) + c := Chat{ Partners: createMessage.Users, GroupChatRemoteID: createMessage.ChatID, @@ -319,16 +331,26 @@ func (s *BoltChatStorage) CreateGroupChatFromMsg(createMessage *AddUserToChat) e func (s *BoltChatStorage) GetGroupChatByRemoteID(id []byte) (*Chat, error) { // make sure chats exist - amount, err := s.db.Count(&Chat{}) + q := s.db.Select(sq.Eq("GroupChatRemoteID", id)) + amount, err := q.Count(&Chat{}) if err != nil { return nil, err } - if amount == 0 { + if amount != 1 { return nil, nil } - c := &Chat{} - return c, s.db.One("GroupChatRemoteID", id, c) + c := &Chat{ + km: s.km, + db: s.db, + postPersistListener: s.postPersistListener, + } + + if err := s.db.One("GroupChatRemoteID", id, c); err != nil { + return nil, err + } + + return c, nil } @@ -338,7 +360,6 @@ func (s *BoltChatStorage) GetChat(chatID int) (*Chat, error) { if err != nil { return nil, err } - if amountChats == 0 { return nil, nil } @@ -348,7 +369,11 @@ func (s *BoltChatStorage) GetChat(chatID int) (*Chat, error) { chat.db = s.db chat.postPersistListener = s.postPersistListener - return chat, s.db.One("ID", amountChats, chat) + if err := s.db.One("ID", chatID, chat); err != nil { + return nil, err + } + + return chat, nil } From 009a263a0eb475a3a8b7736b2d8b4db8fd74b1ea Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Wed, 19 Sep 2018 04:43:33 -0300 Subject: [PATCH 12/38] [fix] small changes --- chat.go | 27 +++++++++------------------ chat/handler.go | 7 +++---- chat/utils.go | 4 ++-- db/chat_storage.go | 6 +++--- 4 files changed, 17 insertions(+), 27 deletions(-) diff --git a/chat.go b/chat.go index a24f36d..631d6f2 100644 --- a/chat.go +++ b/chat.go @@ -91,7 +91,7 @@ func AllChats() (string, error) { chatsRep := []map[string]interface{}{} for _, chat := range chats { chatsRep = append(chatsRep, map[string]interface{}{ - "chat": chat.Partner, + "chat_id": chat.ID, "unread_messages": chat.UnreadMessages, }) } @@ -104,7 +104,7 @@ func AllChats() (string, error) { return string(chatList), nil } -func Messages(partner string, startStr string, amount int) (string, error) { +func Messages(chatID int, startStr string, amount int) (string, error) { // unmarshal start start, err := strconv.ParseInt(startStr, 10, 64) @@ -117,19 +117,18 @@ func Messages(partner string, startStr string, amount int) (string, error) { return "", errors.New("you have to start panthalassa first") } - // partner public key - partnerPub, err := hex.DecodeString(partner) + // fetch chat + chat, err := panthalassaInstance.chatDB.GetChat(chatID) if err != nil { return "", err } - // make sure public key has the right length - if len(partnerPub) != 32 { - return "", errors.New("partner must have a length of 32 bytes") + if chat == nil { + return "", errors.New("chat doesn't exit") } // database messages - databaseMessages, err := panthalassaInstance.chat.Messages(partnerPub, int64(start), uint(amount)) + databaseMessages, err := chat.Messages(start, uint(amount)) if err != nil { return "", err } @@ -167,21 +166,13 @@ func Messages(partner string, startStr string, amount int) (string, error) { } -func MarkMessagesAsRead(partner string) error { +func MarkMessagesAsRead(chatID int) error { // make sure panthalassa has been started if panthalassaInstance == nil { return errors.New("you have to start panthalassa first") } - partnerByte, err := hex.DecodeString(partner) - if err != nil { - return err - } - if len(partnerByte) != 32 { - return errors.New("partner must have length of 32 bytes") - } - - return panthalassaInstance.chat.MarkMessagesAsRead(partnerByte) + return panthalassaInstance.chat.MarkMessagesAsRead(chatID) } diff --git a/chat/handler.go b/chat/handler.go index bb06b51..893722d 100644 --- a/chat/handler.go +++ b/chat/handler.go @@ -2,7 +2,6 @@ package chat import ( "crypto/rand" - "encoding/hex" "encoding/json" "errors" "strconv" @@ -141,7 +140,7 @@ func (c *Chat) handlePersistedMessage(e db.MessagePersistedEvent) { "db_id": strconv.FormatInt(e.Message.UniqueMsgID, 10), "content": string(e.Message.Message), "created_at": e.Message.CreatedAt, - "chat": hex.EncodeToString(e.Chat.Partner), + "chat": e.Chat.ID, "received": e.Message.Received, "dapp": dapp, }) @@ -152,7 +151,7 @@ func (c *Chat) handlePersistedMessage(e db.MessagePersistedEvent) { "db_id": strconv.FormatInt(e.Message.UniqueMsgID, 10), "content": string(e.Message.Message), "created_at": e.Message.CreatedAt, - "chat": hex.EncodeToString(e.Chat.Partner), + "chat": e.Chat.ID, "received": e.Message.Received, "dapp": dapp, }) @@ -163,7 +162,7 @@ func (c *Chat) handlePersistedMessage(e db.MessagePersistedEvent) { "db_id": strconv.FormatInt(e.Message.UniqueMsgID, 10), "content": string(e.Message.Message), "created_at": e.Message.CreatedAt, - "chat": hex.EncodeToString(e.Chat.Partner), + "chat": e.Chat.ID, "received": e.Message.Received, "dapp": dapp, }) diff --git a/chat/utils.go b/chat/utils.go index 0ec88ec..6790d4e 100644 --- a/chat/utils.go +++ b/chat/utils.go @@ -14,8 +14,8 @@ import ( ed25519 "golang.org/x/crypto/ed25519" ) -func (c *Chat) MarkMessagesAsRead(partner ed25519.PublicKey) error { - return c.chatStorage.ReadMessages(partner) +func (c *Chat) MarkMessagesAsRead(chatID int) error { + return c.chatStorage.ReadMessages(chatID) } type drDhPair struct { diff --git a/db/chat_storage.go b/db/chat_storage.go index 6095ee2..5b48dcf 100644 --- a/db/chat_storage.go +++ b/db/chat_storage.go @@ -291,7 +291,7 @@ type ChatStorage interface { // set state of chat to unread messages UnreadMessages(c Chat) error // set state of chat all messages read - ReadMessages(partner ed25519.PublicKey) error + ReadMessages(chatID int) error } type MessagePersistedEvent struct { @@ -415,9 +415,9 @@ func (s *BoltChatStorage) UnreadMessages(c Chat) error { return s.db.Save(&fc) } -func (s *BoltChatStorage) ReadMessages(partner ed25519.PublicKey) error { +func (s *BoltChatStorage) ReadMessages(chatID int) error { var fc Chat - if err := s.db.One("Partner", partner, &fc); err != nil { + if err := s.db.One("ID", chatID, &fc); err != nil { return err } fc.UnreadMessages = false From 733ffb4f2dea3af173338750a6a1fda42a7fae14 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Wed, 19 Sep 2018 14:43:04 -0300 Subject: [PATCH 13/38] [chat] added method to create private chat --- chat.go | 16 ++++++++++++++++ chat/group_chat.go | 6 ++++-- chat/receive_message.go | 3 ++- db/bolt_to_storm.go | 3 ++- db/chat_storage.go | 15 +++++++++++---- 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/chat.go b/chat.go index 631d6f2..4c6f349 100644 --- a/chat.go +++ b/chat.go @@ -48,6 +48,22 @@ func AddUsersToGroupChat(users string, chatID int) error { } +func CreatePrivateChat(partnerStr string) (int, error) { + + // make sure panthalassa has been started + if panthalassaInstance == nil { + return 0, errors.New("you have to start panthalassa first") + } + + partner, err := hex.DecodeString(partnerStr) + if err != nil { + return 0, err + } + + return panthalassaInstance.chatDB.CreateChat(partner) + +} + // return chatID func CreateGroupChat(users string) (int, error) { diff --git a/chat/group_chat.go b/chat/group_chat.go index 295cdea..fe04329 100644 --- a/chat/group_chat.go +++ b/chat/group_chat.go @@ -38,7 +38,8 @@ func (c *Chat) AddUserToGroupChat(partners []ed25519.PublicKey, chatID int) erro return err } if partnerChat == nil { - if err := c.chatStorage.CreateChat(partner); err != nil { + _, err = c.chatStorage.CreateChat(partner) + if err != nil { return err } } @@ -101,7 +102,8 @@ func (c *Chat) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { return 0, err } if partnerChat == nil { - if err := c.chatStorage.CreateChat(partner); err != nil { + _, err = c.chatStorage.CreateChat(partner) + if err != nil { return 0, err } } diff --git a/chat/receive_message.go b/chat/receive_message.go index a38ecca..dac08f3 100644 --- a/chat/receive_message.go +++ b/chat/receive_message.go @@ -122,7 +122,8 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { return err } if chat == nil { - if err := c.chatStorage.CreateChat(msg.Sender); err != nil { + _, err = c.chatStorage.CreateChat(msg.Sender) + if err != nil { return err } } diff --git a/db/bolt_to_storm.go b/db/bolt_to_storm.go index 1e01f72..0d3837d 100644 --- a/db/bolt_to_storm.go +++ b/db/bolt_to_storm.go @@ -289,7 +289,8 @@ func (m *BoltToStormMigration) Migrate(db *storm.DB) error { return chats.ForEach(func(partner, _ []byte) error { - if err := chatDB.CreateChat(partner); err != nil { + _, err := chatDB.CreateChat(partner) + if err != nil { return err } diff --git a/db/chat_storage.go b/db/chat_storage.go index 5b48dcf..64c0097 100644 --- a/db/chat_storage.go +++ b/db/chat_storage.go @@ -283,7 +283,7 @@ type ChatStorage interface { GetChat(chatID int) (*Chat, error) GetGroupChatByRemoteID(id []byte) (*Chat, error) // returned int is the chat ID - CreateChat(partner ed25519.PublicKey) error + CreateChat(partner ed25519.PublicKey) (int, error) CreateGroupChat(partners []ed25519.PublicKey) (int, error) CreateGroupChatFromMsg(createMessage *AddUserToChat) error AddListener(func(e MessagePersistedEvent)) @@ -400,10 +400,17 @@ func (s *BoltChatStorage) GetChatByPartner(partner ed25519.PublicKey) (*Chat, er return &c, nil } -func (s *BoltChatStorage) CreateChat(partner ed25519.PublicKey) error { - return s.db.Save(&Chat{ +func (s *BoltChatStorage) CreateChat(partner ed25519.PublicKey) (int, error) { + + c := &Chat{ Partner: partner, - }) + } + + if err := s.db.Save(c); err != nil { + return 0, err + } + + return c.ID, nil } func (s *BoltChatStorage) UnreadMessages(c Chat) error { From 4dfdf473d4654743fd1fb32a57489bd08570769c Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Wed, 19 Sep 2018 16:52:24 -0300 Subject: [PATCH 14/38] [notary] added signer --- db/bolt_to_storm.go | 2 +- documents/call.go | 12 ++++++++---- keyManager/keyManager.go | 23 +++++++++++++++++++++++ mobile_interface.go | 1 + 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/db/bolt_to_storm.go b/db/bolt_to_storm.go index b712184..f2426f9 100644 --- a/db/bolt_to_storm.go +++ b/db/bolt_to_storm.go @@ -20,7 +20,7 @@ type BoltToStormMigration struct { } func (m *BoltToStormMigration) Migrate(db *storm.DB) error { - + // migrate queue jobs err := db.Bolt.Update(func(tx *bolt.Tx) error { queueStorage := queue.NewStorage(db.WithTransaction(tx)) diff --git a/documents/call.go b/documents/call.go index 827b6c0..9a4c3b6 100644 --- a/documents/call.go +++ b/documents/call.go @@ -8,7 +8,6 @@ import ( keyManager "github.com/Bit-Nation/panthalassa/keyManager" bind "github.com/ethereum/go-ethereum/accounts/abi/bind" common "github.com/ethereum/go-ethereum/common" - types "github.com/ethereum/go-ethereum/core/types" cid "github.com/ipfs/go-cid" mh "github.com/multiformats/go-multihash" ) @@ -250,12 +249,17 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int // attach signature to doc doc.Signature = cidSignature + idKey, err := d.km.IdentityPublicKey() + if err != nil { + return map[string]interface{}{}, err + } + // submit tx to chain tx, err := d.n.NotarizeTwo(&bind.TransactOpts{ - Signer: func(signer types.Signer, addresses common.Address, transaction *types.Transaction) (*types.Transaction, error) { - return transaction, nil - }, + From: common.HexToAddress(idKey), + Signer: d.km.SignEthTx, }, d.notaryAddr, docContentCID, cidSignature) + tx.Data() if err != nil { return map[string]interface{}{}, err } diff --git a/keyManager/keyManager.go b/keyManager/keyManager.go index 8a79cc1..27afef3 100644 --- a/keyManager/keyManager.go +++ b/keyManager/keyManager.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" + api "github.com/Bit-Nation/panthalassa/api" aes "github.com/Bit-Nation/panthalassa/crypto/aes" scrypt "github.com/Bit-Nation/panthalassa/crypto/scrypt" ks "github.com/Bit-Nation/panthalassa/keyStore" @@ -14,6 +15,8 @@ import ( identity "github.com/Bit-Nation/panthalassa/keyStore/migration/identity" mnemonic "github.com/Bit-Nation/panthalassa/mnemonic" x3dh "github.com/Bit-Nation/x3dh" + common "github.com/ethereum/go-ethereum/common" + types "github.com/ethereum/go-ethereum/core/types" ethCrypto "github.com/ethereum/go-ethereum/crypto" lp2pCrypto "github.com/libp2p/go-libp2p-crypto" ed25519 "golang.org/x/crypto/ed25519" @@ -22,6 +25,7 @@ import ( type KeyManager struct { keyStore ks.Store account Store + Api *api.API } type Store struct { @@ -277,6 +281,25 @@ func (km KeyManager) AESEncrypt(plainText aes.PlainText) (aes.CipherText, error) return aes.CTREncrypt(plainText, aesSecret) } +func (km KeyManager) SignEthTx(signer types.Signer, addresses common.Address, tx *types.Transaction) (*types.Transaction, error) { + + submittedTx, err := km.api.SendEthereumTransaction( + tx.Value().String(), + tx.To().String(), + hex.EncodeToString(tx.Data()), + ) + if err != nil { + return nil, err + } + + signedTx := &types.Transaction{} + if err := signedTx.UnmarshalJSON([]byte(submittedTx)); err != nil { + return nil, err + } + + return signedTx, nil +} + func (km KeyManager) ChatIdKeyPair() (x3dh.KeyPair, error) { strPriv, err := km.keyStore.GetKey(chatMigration.MigrationPrivPrefix) diff --git a/mobile_interface.go b/mobile_interface.go index a8fcbb3..b27e0e1 100644 --- a/mobile_interface.go +++ b/mobile_interface.go @@ -62,6 +62,7 @@ func start(dbDir string, km *keyManager.KeyManager, config StartConfig, client, // device api deviceApi := api.New(client) + km.Api = deviceApi // create p2p network p2pNetwork, err := p2p.New() From 8733c8e2d0873dfad014439574e5631024d929ce Mon Sep 17 00:00:00 2001 From: Andrii Selivanov Date: Wed, 19 Sep 2018 23:06:31 +0300 Subject: [PATCH 15/38] [notary] Fixed typo. --- keyManager/keyManager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keyManager/keyManager.go b/keyManager/keyManager.go index 27afef3..81b2f73 100644 --- a/keyManager/keyManager.go +++ b/keyManager/keyManager.go @@ -283,7 +283,7 @@ func (km KeyManager) AESEncrypt(plainText aes.PlainText) (aes.CipherText, error) func (km KeyManager) SignEthTx(signer types.Signer, addresses common.Address, tx *types.Transaction) (*types.Transaction, error) { - submittedTx, err := km.api.SendEthereumTransaction( + submittedTx, err := km.Api.SendEthereumTransaction( tx.Value().String(), tx.To().String(), hex.EncodeToString(tx.Data()), From 0c2d82502a01d69e9b408ffd680d1028f7945288 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Wed, 19 Sep 2018 17:10:51 -0300 Subject: [PATCH 16/38] [notary] fix for submit --- documents/call.go | 1 - keyManager/keyManager.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/documents/call.go b/documents/call.go index 9a4c3b6..c320949 100644 --- a/documents/call.go +++ b/documents/call.go @@ -259,7 +259,6 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int From: common.HexToAddress(idKey), Signer: d.km.SignEthTx, }, d.notaryAddr, docContentCID, cidSignature) - tx.Data() if err != nil { return map[string]interface{}{}, err } diff --git a/keyManager/keyManager.go b/keyManager/keyManager.go index 27afef3..81b2f73 100644 --- a/keyManager/keyManager.go +++ b/keyManager/keyManager.go @@ -283,7 +283,7 @@ func (km KeyManager) AESEncrypt(plainText aes.PlainText) (aes.CipherText, error) func (km KeyManager) SignEthTx(signer types.Signer, addresses common.Address, tx *types.Transaction) (*types.Transaction, error) { - submittedTx, err := km.api.SendEthereumTransaction( + submittedTx, err := km.Api.SendEthereumTransaction( tx.Value().String(), tx.To().String(), hex.EncodeToString(tx.Data()), From c8cc6407103709ef87424da91b7ef7b671798d14 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Sun, 23 Sep 2018 20:58:00 -0700 Subject: [PATCH 17/38] [docs] fixed eth sign action --- documents/call.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documents/call.go b/documents/call.go index c320949..b43441c 100644 --- a/documents/call.go +++ b/documents/call.go @@ -249,14 +249,14 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int // attach signature to doc doc.Signature = cidSignature - idKey, err := d.km.IdentityPublicKey() + ethAddr, err := d.km.GetEthereumAddress() if err != nil { return map[string]interface{}{}, err } // submit tx to chain tx, err := d.n.NotarizeTwo(&bind.TransactOpts{ - From: common.HexToAddress(idKey), + From: common.HexToAddress(ethAddr), Signer: d.km.SignEthTx, }, d.notaryAddr, docContentCID, cidSignature) if err != nil { From d726f39b331f2c5b3a7c29d00e059028aaf8ecba Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Mon, 24 Sep 2018 19:34:01 -0700 Subject: [PATCH 18/38] [documents] fixed notary calls --- Gopkg.lock | 256 ++++++++++++++++++++++++++++++++++- documents/call.go | 18 ++- documents/notary_contract.go | 60 +++++--- mobile_interface.go | 10 +- 4 files changed, 306 insertions(+), 38 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 1513661..cc659ae 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -25,6 +25,12 @@ packages = ["."] revision = "d3a63a5752ecf3fbc06bd97365da752111c263df" +[[projects]] + branch = "master" + name = "github.com/NaySoftware/go-fcm" + packages = ["."] + revision = "28fff9381d17f35619309c7a5ada41d26030d976" + [[projects]] branch = "master" name = "github.com/agl/ed25519" @@ -54,12 +60,31 @@ revision = "5a6fe65e3993f63951c8e3f64c812536c9e23595" version = "v2.1.2" +[[projects]] + branch = "master" + name = "github.com/beorn7/perks" + packages = ["quantile"] + revision = "3a771d992973f24aa725d07868b467d1ddfceafb" + [[projects]] branch = "master" name = "github.com/btcsuite/btcd" - packages = ["btcec"] + packages = [ + "btcec", + "chaincfg", + "chaincfg/chainhash", + "wire" + ] revision = "f673a4b563b57b9a95832545c878669a7fa801d9" +[[projects]] + name = "github.com/btcsuite/btcutil" + packages = [ + ".", + "base58" + ] + revision = "dcd4997b0664bcfd6ef48e4ae9da8396e08b1cd9" + [[projects]] name = "github.com/coreos/bbolt" packages = ["."] @@ -84,6 +109,12 @@ revision = "1d4478f51bed434f1dadf96dcd9b43aabac66795" version = "v1.7" +[[projects]] + branch = "master" + name = "github.com/edsrzf/mmap-go" + packages = ["."] + revision = "0bce6a6887123b67a60366d2c9fe2dfb74289d2e" + [[projects]] name = "github.com/ethereum/go-ethereum" packages = [ @@ -92,24 +123,64 @@ "accounts/abi", "accounts/abi/bind", "accounts/keystore", + "accounts/usbwallet", + "accounts/usbwallet/internal/trezor", "common", + "common/bitutil", + "common/fdlimit", "common/hexutil", "common/math", "common/mclock", + "common/prque", + "consensus", + "consensus/clique", + "consensus/ethash", + "consensus/misc", + "core", + "core/bloombits", + "core/rawdb", + "core/state", "core/types", + "core/vm", "crypto", + "crypto/bn256", + "crypto/bn256/cloudflare", + "crypto/bn256/google", + "crypto/ecies", "crypto/secp256k1", "crypto/sha3", + "eth", + "eth/downloader", + "eth/fetcher", + "eth/filters", + "eth/gasprice", + "eth/tracers", + "eth/tracers/internal/tracers", "ethclient", "ethdb", "event", + "internal/debug", + "internal/ethapi", + "les", + "les/flowcontrol", + "light", "log", + "log/term", "metrics", + "metrics/exp", + "miner", + "node", + "p2p", + "p2p/discover", + "p2p/discv5", + "p2p/nat", "p2p/netutil", "params", "rlp", "rpc", - "trie" + "trie", + "whisper/mailserver", + "whisper/whisperv6" ] revision = "89451f7c382ad2185987ee369f16416f89c28a7d" version = "v1.8.15" @@ -120,6 +191,30 @@ revision = "bad65a492f32121a87197f4a085905c35e2a367e" version = "v1.0.0" +[[projects]] + branch = "master" + name = "github.com/fjl/memsize" + packages = [ + ".", + "memsizeui" + ] + revision = "f6d5545993d68e9e42df43eb57958f898dea3623" + +[[projects]] + name = "github.com/go-playground/locales" + packages = [ + ".", + "currency" + ] + revision = "f63010822830b6fe52288ee52d5a1151088ce039" + version = "v0.12.1" + +[[projects]] + name = "github.com/go-playground/universal-translator" + packages = ["."] + revision = "b32fa301c9fe55953584134cb6853a13c87ec0a1" + version = "v0.16.0" + [[projects]] name = "github.com/go-stack/stack" packages = ["."] @@ -135,9 +230,18 @@ revision = "636bf0302bc95575d69441b25a2603156ffdddf1" version = "v1.1.1" +[[projects]] + name = "github.com/golang/mock" + packages = ["gomock"] + revision = "c34cdb4725f4c3844d095133c6e40e448b86589b" + version = "v1.1.1" + [[projects]] name = "github.com/golang/protobuf" - packages = ["proto"] + packages = [ + "proto", + "protoc-gen-go/descriptor" + ] revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" version = "v1.1.0" @@ -183,6 +287,15 @@ packages = ["."] revision = "80a92cca79a8041496ccc9dd773fcb52a57ec6f9" +[[projects]] + name = "github.com/hashicorp/golang-lru" + packages = [ + ".", + "simplelru" + ] + revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" + version = "v0.5.0" + [[projects]] branch = "master" name = "github.com/huin/goupnp" @@ -255,6 +368,12 @@ ] revision = "b497e2f366b8624394fb2e89c10ab607bebdde0b" +[[projects]] + branch = "master" + name = "github.com/karalabe/hid" + packages = ["."] + revision = "2b4488a37358b7283de4f9622553e85ebbe73125" + [[projects]] name = "github.com/kataras/iris" packages = ["core/errors"] @@ -475,6 +594,12 @@ revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" version = "v0.0.3" +[[projects]] + name = "github.com/matttproud/golang_protobuf_extensions" + packages = ["pbutil"] + revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" + version = "v1.0.1" + [[projects]] branch = "master" name = "github.com/minio/sha256-simd" @@ -551,12 +676,65 @@ revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" +[[projects]] + name = "github.com/prometheus/client_golang" + packages = ["prometheus"] + revision = "c5b7fccd204277076155f10851dad72b76a49317" + version = "v0.8.0" + +[[projects]] + branch = "master" + name = "github.com/prometheus/client_model" + packages = ["go"] + revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f" + +[[projects]] + branch = "master" + name = "github.com/prometheus/common" + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "model" + ] + revision = "c7de2306084e37d54b8be01f3541a8464345e9a5" + +[[projects]] + branch = "master" + name = "github.com/prometheus/procfs" + packages = [ + ".", + "internal/util", + "nfs", + "xfs" + ] + revision = "418d78d0b9a7b7de3a6bbc8a23def624cc977bb2" + +[[projects]] + name = "github.com/prometheus/prometheus" + packages = ["util/flock"] + revision = "85f23d82a045d103ea7f3c89a91fba4a93e6367a" + version = "v2.1.0" + [[projects]] name = "github.com/rjeczalik/notify" packages = ["."] revision = "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8" version = "v0.9.1" +[[projects]] + branch = "master" + name = "github.com/robertkrimen/otto" + packages = [ + ".", + "ast", + "dbg", + "file", + "parser", + "registry", + "token" + ] + revision = "15f95af6e78dcd2030d8195a138bd88d4f403546" + [[projects]] name = "github.com/rs/cors" packages = ["."] @@ -569,6 +747,43 @@ revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3" version = "v1.2.0" +[[projects]] + name = "github.com/status-im/go-web3js" + packages = ["."] + revision = "a136c82b1e1f30b5b24118eeff1caa71924e4e3a" + version = "0.20.1" + +[[projects]] + branch = "experimental/fix-logging-old" + name = "github.com/status-im/status-go" + packages = [ + "extkeys", + "geth/account", + "geth/api", + "geth/db", + "geth/jail", + "geth/jail/console", + "geth/jail/internal/fetch", + "geth/jail/internal/loop", + "geth/jail/internal/loop/looptask", + "geth/jail/internal/promise", + "geth/jail/internal/timers", + "geth/jail/internal/vm", + "geth/mailservice", + "geth/node", + "geth/notifications/push/fcm", + "geth/params", + "geth/peers", + "geth/rpc", + "geth/signal", + "geth/transactions", + "metrics/whisper", + "shhext", + "sign", + "static" + ] + revision = "4f8a957fbb40b74b90a0ebe2c7b80c55c0dc16a6" + [[projects]] name = "github.com/stretchr/testify" packages = [ @@ -706,10 +921,17 @@ ] revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0" +[[projects]] + branch = "master" + name = "golang.org/x/sync" + packages = ["syncmap"] + revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" + [[projects]] branch = "master" name = "golang.org/x/sys" packages = [ + "cpu", "unix", "windows" ] @@ -730,11 +952,14 @@ "encoding/unicode", "internal/gen", "internal/tag", + "internal/triegen", + "internal/ucd", "internal/utf8internal", "language", "runes", "transform", - "unicode/cldr" + "unicode/cldr", + "unicode/norm" ] revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" @@ -749,6 +974,12 @@ ] revision = "677d2ff680c188ddb7dcd2bfa6bc7d3f2f2f75b2" +[[projects]] + name = "gopkg.in/go-playground/validator.v9" + packages = ["."] + revision = "e69e9a28bb62b977fdc58d051f1bb477b7cbe486" + version = "v9.21.0" + [[projects]] branch = "v2" name = "gopkg.in/karalabe/cookiejar.v2" @@ -767,9 +998,24 @@ packages = ["."] revision = "d53328019b21fe1987c97f368f98c072c8f44455" +[[projects]] + name = "gopkg.in/sourcemap.v1" + packages = [ + ".", + "base64vlq" + ] + revision = "6e83acea0053641eff084973fee085f0c193c61a" + version = "v1.0.5" + +[[projects]] + name = "gopkg.in/urfave/cli.v1" + packages = ["."] + revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1" + version = "v1.20.0" + [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "298a8ade8ec5b9208e922a5f62e91e7b5151af951b74f5781adc62455395a574" + inputs-digest = "259be0c4cd8a1b7192860ea4411e31bc27b7226a00882ec894176a86fcc76c74" solver-name = "gps-cdcl" solver-version = 1 diff --git a/documents/call.go b/documents/call.go index b43441c..a4d4c47 100644 --- a/documents/call.go +++ b/documents/call.go @@ -194,18 +194,16 @@ func (d *DocumentDeleteCall) Handle(data map[string]interface{}) (map[string]int } type DocumentSubmitCall struct { - s *Storage - km *keyManager.KeyManager - n *NotaryMulti - notaryAddr common.Address + s *Storage + km *keyManager.KeyManager + n *NotaryMulti } -func NewDocumentNotariseCall(s *Storage, km *keyManager.KeyManager, n *NotaryMulti, notaryAddr common.Address) *DocumentSubmitCall { +func NewDocumentNotariseCall(s *Storage, km *keyManager.KeyManager, n *NotaryMulti) *DocumentSubmitCall { return &DocumentSubmitCall{ - s: s, - km: km, - n: n, - notaryAddr: notaryAddr, + s: s, + km: km, + n: n, } } @@ -258,7 +256,7 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int tx, err := d.n.NotarizeTwo(&bind.TransactOpts{ From: common.HexToAddress(ethAddr), Signer: d.km.SignEthTx, - }, d.notaryAddr, docContentCID, cidSignature) + }, docContentCID, cidSignature) if err != nil { return map[string]interface{}{}, err } diff --git a/documents/notary_contract.go b/documents/notary_contract.go index 43c28f6..9a89e80 100644 --- a/documents/notary_contract.go +++ b/documents/notary_contract.go @@ -17,7 +17,7 @@ import ( const NotaryABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"records\",\"outputs\":[{\"name\":\"notarisedData\",\"type\":\"bytes\"},{\"name\":\"timestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_notarisedData\",\"type\":\"bytes\"}],\"name\":\"record\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"},{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_record\",\"type\":\"bytes\"}],\"name\":\"notarize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" // NotaryBin is the compiled bytecode used for deploying new contracts. -const NotaryBin = `0x608060405234801561001057600080fd5b50610522806100206000396000f3006080604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166301e64725811461005b578063e1112648146100f2578063fb1ace341461014b575b600080fd5b34801561006757600080fd5b506100736004356101a6565b6040518080602001838152602001828103825284818151815260200191508051906020019080838360005b838110156100b657818101518382015260200161009e565b50505050905090810190601f1680156100e35780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156100fe57600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261007394369492936024939284019190819084018382808284375094975061024a9650505050505050565b34801561015757600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526101a494369492936024939284019190819084018382808284375094975061037e9650505050505050565b005b6000602081815291815260409081902080548251601f60026000196101006001861615020190931692909204918201859004850281018501909352808352909283919083018282801561023a5780601f1061020f5761010080835404028352916020019161023a565b820191906000526020600020905b81548152906001019060200180831161021d57829003601f168201915b5050505050908060010154905082565b60606000610256610443565b600080856040518082805190602001908083835b602083106102895780518252601f19909201916020918201910161026a565b518151600019602094850361010090810a8201928316921993909316919091179092526040805196909401869003909520885287820198909852958101600020815181546060601f60026001841615909802909b019091169590950498890188900490970287018401825290860187815295969095879550935085929091508401828280156103595780601f1061032e57610100808354040283529160200191610359565b820191906000526020600020905b81548152906001019060200180831161033c57829003601f168201915b5050509183525050600191909101546020918201528151910151909590945092505050565b6000816040518082805190602001908083835b602083106103b05780518252601f199092019160209182019101610391565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181529182905292902060010154919450501591506103fa905057600080fd5b604080518082018252838152426020808301919091526000848152808252929092208151805192939192610431928492019061045b565b50602082015181600101559050505050565b60408051808201909152606081526000602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061049c57805160ff19168380011785556104c9565b828001600101855582156104c9579182015b828111156104c95782518255916020019190600101906104ae565b506104d59291506104d9565b5090565b6104f391905b808211156104d557600081556001016104df565b905600a165627a7a72305820b7df842df5393139052e21c871c46429425f1394048c184e0e0e7b58843ea51b0029` +const NotaryBin = `0x608060405234801561001057600080fd5b50610522806100206000396000f3006080604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166301e64725811461005b578063e1112648146100f2578063fb1ace341461014b575b600080fd5b34801561006757600080fd5b506100736004356101a6565b6040518080602001838152602001828103825284818151815260200191508051906020019080838360005b838110156100b657818101518382015260200161009e565b50505050905090810190601f1680156100e35780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156100fe57600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261007394369492936024939284019190819084018382808284375094975061024a9650505050505050565b34801561015757600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526101a494369492936024939284019190819084018382808284375094975061037e9650505050505050565b005b6000602081815291815260409081902080548251601f60026000196101006001861615020190931692909204918201859004850281018501909352808352909283919083018282801561023a5780601f1061020f5761010080835404028352916020019161023a565b820191906000526020600020905b81548152906001019060200180831161021d57829003601f168201915b5050505050908060010154905082565b60606000610256610443565b600080856040518082805190602001908083835b602083106102895780518252601f19909201916020918201910161026a565b518151600019602094850361010090810a8201928316921993909316919091179092526040805196909401869003909520885287820198909852958101600020815181546060601f60026001841615909802909b019091169590950498890188900490970287018401825290860187815295969095879550935085929091508401828280156103595780601f1061032e57610100808354040283529160200191610359565b820191906000526020600020905b81548152906001019060200180831161033c57829003601f168201915b5050509183525050600191909101546020918201528151910151909590945092505050565b6000816040518082805190602001908083835b602083106103b05780518252601f199092019160209182019101610391565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181529182905292902060010154919450501591506103fa905057600080fd5b604080518082018252838152426020808301919091526000848152808252929092208151805192939192610431928492019061045b565b50602082015181600101559050505050565b60408051808201909152606081526000602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061049c57805160ff19168380011785556104c9565b828001600101855582156104c9579182015b828111156104c95782518255916020019190600101906104ae565b506104d59291506104d9565b5090565b6104f391905b808211156104d557600081556001016104df565b905600a165627a7a723058202f26cafc2d47e2fe82a1fda2aa083df782fc0d1b534c8ea261ea634441b4403f0029` // DeployNotary deploys a new Ethereum contract, binding an instance of Notary to it. func DeployNotary(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Notary, error) { @@ -262,18 +262,18 @@ func (_Notary *NotaryTransactorSession) Notarize(_record []byte) (*types.Transac } // NotaryMultiABI is the input ABI used to generate the binding from. -const NotaryMultiABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_notaryAddress\",\"type\":\"address\"},{\"name\":\"_firstRecord\",\"type\":\"bytes\"},{\"name\":\"_secondRecord\",\"type\":\"bytes\"}],\"name\":\"notarizeTwo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" +const NotaryMultiABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_firstRecord\",\"type\":\"bytes\"},{\"name\":\"_secondRecord\",\"type\":\"bytes\"}],\"name\":\"notarizeTwo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"notary\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_notary\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]" // NotaryMultiBin is the compiled bytecode used for deploying new contracts. -const NotaryMultiBin = `0x608060405234801561001057600080fd5b506102fb806100206000396000f3006080604052600436106100405763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416636ca484d78114610045575b600080fd5b34801561005157600080fd5b5060408051602060046024803582810135601f81018590048502860185019096528585526100f795833573ffffffffffffffffffffffffffffffffffffffff1695369560449491939091019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a9998810197919650918201945092508291508401838280828437509497506100f99650505050505050565b005b6040517ffb1ace34000000000000000000000000000000000000000000000000000000008152602060048201818152845160248401528451869373ffffffffffffffffffffffffffffffffffffffff85169363fb1ace34938893909283926044909101919085019080838360005b8381101561017f578181015183820152602001610167565b50505050905090810190601f1680156101ac5780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b1580156101cb57600080fd5b505af11580156101df573d6000803e3d6000fd5b50506040517ffb1ace3400000000000000000000000000000000000000000000000000000000815260206004820181815286516024840152865173ffffffffffffffffffffffffffffffffffffffff8716955063fb1ace349450879391928392604401919085019080838360005b8381101561026557818101518382015260200161024d565b50505050905090810190601f1680156102925780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b1580156102b157600080fd5b505af11580156102c5573d6000803e3d6000fd5b50505050505050505600a165627a7a723058209ccebce4442a22d9a140fb00f0dd8f77d860725161bd44fae7bc44697f557b250029` +const NotaryMultiBin = `0x608060405234801561001057600080fd5b5060405160208061039d833981016040525160008054600160a060020a03909216600160a060020a031990921691909117905561034b806100526000396000f30060806040526004361061004b5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630926778581146100505780639d54c79d146100e9575b600080fd5b34801561005c57600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526100e794369492936024939284019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a9998810197919650918201945092508291508401838280828437509497506101279650505050505050565b005b3480156100f557600080fd5b506100fe610303565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b600080546040517ffb1ace3400000000000000000000000000000000000000000000000000000000815260206004820181815286516024840152865173ffffffffffffffffffffffffffffffffffffffff9094169463fb1ace34948894929384936044019290860191908190849084905b838110156101b0578181015183820152602001610198565b50505050905090810190601f1680156101dd5780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b1580156101fc57600080fd5b505af1158015610210573d6000803e3d6000fd5b5050600080546040517ffb1ace3400000000000000000000000000000000000000000000000000000000815260206004820181815287516024840152875173ffffffffffffffffffffffffffffffffffffffff909416965063fb1ace349550879490938493604401928601918190849084905b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b1580156102e757600080fd5b505af11580156102fb573d6000803e3d6000fd5b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a7230582067c4bd5c4a01e384e114aa1703b959f06b936b1861ad7cc7548b8f3d018807130029` // DeployNotaryMulti deploys a new Ethereum contract, binding an instance of NotaryMulti to it. -func DeployNotaryMulti(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *NotaryMulti, error) { +func DeployNotaryMulti(auth *bind.TransactOpts, backend bind.ContractBackend, _notary common.Address) (common.Address, *types.Transaction, *NotaryMulti, error) { parsed, err := abi.JSON(strings.NewReader(NotaryMultiABI)) if err != nil { return common.Address{}, nil, nil, err } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(NotaryMultiBin), backend) + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(NotaryMultiBin), backend, _notary) if err != nil { return common.Address{}, nil, nil, err } @@ -422,23 +422,49 @@ func (_NotaryMulti *NotaryMultiTransactorRaw) Transact(opts *bind.TransactOpts, return _NotaryMulti.Contract.contract.Transact(opts, method, params...) } -// NotarizeTwo is a paid mutator transaction binding the contract method 0x6ca484d7. +// Notary is a free data retrieval call binding the contract method 0x9d54c79d. // -// Solidity: function notarizeTwo(_notaryAddress address, _firstRecord bytes, _secondRecord bytes) returns() -func (_NotaryMulti *NotaryMultiTransactor) NotarizeTwo(opts *bind.TransactOpts, _notaryAddress common.Address, _firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { - return _NotaryMulti.contract.Transact(opts, "notarizeTwo", _notaryAddress, _firstRecord, _secondRecord) +// Solidity: function notary() constant returns(address) +func (_NotaryMulti *NotaryMultiCaller) Notary(opts *bind.CallOpts) (common.Address, error) { + var ( + ret0 = new(common.Address) + ) + out := ret0 + err := _NotaryMulti.contract.Call(opts, out, "notary") + return *ret0, err +} + +// Notary is a free data retrieval call binding the contract method 0x9d54c79d. +// +// Solidity: function notary() constant returns(address) +func (_NotaryMulti *NotaryMultiSession) Notary() (common.Address, error) { + return _NotaryMulti.Contract.Notary(&_NotaryMulti.CallOpts) +} + +// Notary is a free data retrieval call binding the contract method 0x9d54c79d. +// +// Solidity: function notary() constant returns(address) +func (_NotaryMulti *NotaryMultiCallerSession) Notary() (common.Address, error) { + return _NotaryMulti.Contract.Notary(&_NotaryMulti.CallOpts) +} + +// NotarizeTwo is a paid mutator transaction binding the contract method 0x09267785. +// +// Solidity: function notarizeTwo(_firstRecord bytes, _secondRecord bytes) returns() +func (_NotaryMulti *NotaryMultiTransactor) NotarizeTwo(opts *bind.TransactOpts, _firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { + return _NotaryMulti.contract.Transact(opts, "notarizeTwo", _firstRecord, _secondRecord) } -// NotarizeTwo is a paid mutator transaction binding the contract method 0x6ca484d7. +// NotarizeTwo is a paid mutator transaction binding the contract method 0x09267785. // -// Solidity: function notarizeTwo(_notaryAddress address, _firstRecord bytes, _secondRecord bytes) returns() -func (_NotaryMulti *NotaryMultiSession) NotarizeTwo(_notaryAddress common.Address, _firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { - return _NotaryMulti.Contract.NotarizeTwo(&_NotaryMulti.TransactOpts, _notaryAddress, _firstRecord, _secondRecord) +// Solidity: function notarizeTwo(_firstRecord bytes, _secondRecord bytes) returns() +func (_NotaryMulti *NotaryMultiSession) NotarizeTwo(_firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { + return _NotaryMulti.Contract.NotarizeTwo(&_NotaryMulti.TransactOpts, _firstRecord, _secondRecord) } -// NotarizeTwo is a paid mutator transaction binding the contract method 0x6ca484d7. +// NotarizeTwo is a paid mutator transaction binding the contract method 0x09267785. // -// Solidity: function notarizeTwo(_notaryAddress address, _firstRecord bytes, _secondRecord bytes) returns() -func (_NotaryMulti *NotaryMultiTransactorSession) NotarizeTwo(_notaryAddress common.Address, _firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { - return _NotaryMulti.Contract.NotarizeTwo(&_NotaryMulti.TransactOpts, _notaryAddress, _firstRecord, _secondRecord) +// Solidity: function notarizeTwo(_firstRecord bytes, _secondRecord bytes) returns() +func (_NotaryMulti *NotaryMultiTransactorSession) NotarizeTwo(_firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { + return _NotaryMulti.Contract.NotarizeTwo(&_NotaryMulti.TransactOpts, _firstRecord, _secondRecord) } diff --git a/mobile_interface.go b/mobile_interface.go index b27e0e1..b4a5dd7 100644 --- a/mobile_interface.go +++ b/mobile_interface.go @@ -154,8 +154,7 @@ func start(dbDir string, km *keyManager.KeyManager, config StartConfig, client, return err } - var notaryMulti common.Address - var notary common.Address + var notaryMultiAddr common.Address networkID, err := ethClient.NetworkID(context.Background()) if err != nil { @@ -168,14 +167,13 @@ func start(dbDir string, km *keyManager.KeyManager, config StartConfig, client, } // rinkeby addresses - notary = common.HexToAddress("0xd75afa5c92cefded2862d2770f6a0929af74067d") - notaryMulti = common.HexToAddress("0x00d238247ae4324f952d2c9a297dd5f76ed0e7c0") + notaryMultiAddr = common.HexToAddress("0x5e04e983bb438d70471848d7f24416fa0a9a7de1") - notaryContract, err := documents.NewNotaryMulti(notaryMulti, ethClient) + notaryContract, err := documents.NewNotaryMulti(notaryMultiAddr, ethClient) if err != nil { return err } - notariseCall := documents.NewDocumentNotariseCall(docStorage, km, notaryContract, notary) + notariseCall := documents.NewDocumentNotariseCall(docStorage, km, notaryContract) if err := dcr.Register(notariseCall); err != nil { return err } From 69e7970338b42e2cfcbcbcb94a00ead1964c9899 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 25 Sep 2018 11:04:58 -0700 Subject: [PATCH 19/38] [api] changed tx data --- api/dapp.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/api/dapp.go b/api/dapp.go index 5f48b18..1c92ada 100644 --- a/api/dapp.go +++ b/api/dapp.go @@ -66,14 +66,13 @@ func (a *DAppApi) SendEthereumTransaction(value, to, data string) (string, error objTx := map[string]interface{}{ "nonce": ethTx.Nonce, "gasPrice": ethTx.GasPrice, - "gasLimit": ethTx.GasLimit, + "gas": ethTx.GasLimit, "to": ethTx.To, "value": ethTx.Value, - "data": ethTx.Data, + "input": ethTx.Data, "v": ethTx.V, "r": ethTx.R, "s": ethTx.S, - "chainId": ethTx.ChainID, "from": ethTx.From, "hash": ethTx.Hash, } From 102df01b89af7fde4a1763f310c7bbac036221a0 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 25 Sep 2018 15:45:11 -0700 Subject: [PATCH 20/38] [km] fix for signing with int encoding --- keyManager/keyManager.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/keyManager/keyManager.go b/keyManager/keyManager.go index 81b2f73..9f53f01 100644 --- a/keyManager/keyManager.go +++ b/keyManager/keyManager.go @@ -16,10 +16,12 @@ import ( mnemonic "github.com/Bit-Nation/panthalassa/mnemonic" x3dh "github.com/Bit-Nation/x3dh" common "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" types "github.com/ethereum/go-ethereum/core/types" ethCrypto "github.com/ethereum/go-ethereum/crypto" lp2pCrypto "github.com/libp2p/go-libp2p-crypto" ed25519 "golang.org/x/crypto/ed25519" + "strconv" ) type KeyManager struct { @@ -292,6 +294,23 @@ func (km KeyManager) SignEthTx(signer types.Signer, addresses common.Address, tx return nil, err } + // unmarshal tx + var txMap map[string]interface{} + if err := json.Unmarshal([]byte(submittedTx), &txMap); err != nil { + return nil, err + } + + // turn gas price into hex + gasPriceStr, ok := txMap["gasPrice"].(string) + if ok { + return nil, errors.New("gas price must be a string") + } + gasPrice, err := strconv.Atoi(gasPriceStr) + if err != nil { + return nil, err + } + txMap["gasPrice"] = "0x" + strconv.FormatInt(int64(gasPrice), 16) + signedTx := &types.Transaction{} if err := signedTx.UnmarshalJSON([]byte(submittedTx)); err != nil { return nil, err From 1d9329ddeff256601097af636d25040fb67d25de Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 25 Sep 2018 16:48:31 -0700 Subject: [PATCH 21/38] [km] added tx transform for unmarshal tx --- keyManager/keyManager.go | 73 +++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/keyManager/keyManager.go b/keyManager/keyManager.go index 9f53f01..d3407a2 100644 --- a/keyManager/keyManager.go +++ b/keyManager/keyManager.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "encoding/json" "errors" + "strconv" api "github.com/Bit-Nation/panthalassa/api" aes "github.com/Bit-Nation/panthalassa/crypto/aes" @@ -16,12 +17,10 @@ import ( mnemonic "github.com/Bit-Nation/panthalassa/mnemonic" x3dh "github.com/Bit-Nation/x3dh" common "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" types "github.com/ethereum/go-ethereum/core/types" ethCrypto "github.com/ethereum/go-ethereum/crypto" lp2pCrypto "github.com/libp2p/go-libp2p-crypto" ed25519 "golang.org/x/crypto/ed25519" - "strconv" ) type KeyManager struct { @@ -294,25 +293,81 @@ func (km KeyManager) SignEthTx(signer types.Signer, addresses common.Address, tx return nil, err } + // convert to ethereum hex string + numToHex := func(txData map[string]interface{}, toTransform string) (string, error) { + + gasPriceStr, ok := txData["gasPrice"].(string) + if ok { + return "", errors.New("gas price must be a string") + } + gasPrice, err := strconv.Atoi(gasPriceStr) + if err != nil { + return "", err + } + + return "0x" + strconv.FormatInt(int64(gasPrice), 16), nil + + } + // unmarshal tx var txMap map[string]interface{} if err := json.Unmarshal([]byte(submittedTx), &txMap); err != nil { return nil, err } - // turn gas price into hex - gasPriceStr, ok := txMap["gasPrice"].(string) - if ok { - return nil, errors.New("gas price must be a string") + // convert nonce + txMap["nonce"], err = numToHex(txMap, "nonce") + if err != nil { + return nil, err + } + + // convert gas price + txMap["gasPrice"], err = numToHex(txMap, "gasPrice") + if err != nil { + return nil, err } - gasPrice, err := strconv.Atoi(gasPriceStr) + + // convert gas + txMap["gas"], err = numToHex(txMap, "gas") + if err != nil { + return nil, err + } + + // convert value + txMap["value"], err = numToHex(txMap, "value") + if err != nil { + return nil, err + } + + // map input + txMap["input"] = txMap["data"] + + // convert signature v + txMap["v"], err = numToHex(txMap, "v") + if err != nil { + return nil, err + } + + // convert signature r + txMap["r"], err = numToHex(txMap, "r") + if err != nil { + return nil, err + } + + // convert signature s + txMap["s"], err = numToHex(txMap, "s") + if err != nil { + return nil, err + } + + // turn mutated transaction into encoded json + txJson, err := json.Marshal(txMap) if err != nil { return nil, err } - txMap["gasPrice"] = "0x" + strconv.FormatInt(int64(gasPrice), 16) signedTx := &types.Transaction{} - if err := signedTx.UnmarshalJSON([]byte(submittedTx)); err != nil { + if err := signedTx.UnmarshalJSON(txJson); err != nil { return nil, err } From ba9897c9d00c71445c260d05b7fb389347137d0f Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 25 Sep 2018 18:47:23 -0700 Subject: [PATCH 22/38] [chat] fixed chat return arguments --- chat/save_message_test.go | 3 ++- chat/send_and_receive_func_test.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/chat/save_message_test.go b/chat/save_message_test.go index 6f6fd09..140897b 100644 --- a/chat/save_message_test.go +++ b/chat/save_message_test.go @@ -23,7 +23,8 @@ func TestChat_SavePrivateMessage(t *testing.T) { km: km, } - require.Nil(t, chatStorage.CreateChat(pub)) + _, err = chatStorage.CreateChat(pub) + require.Nil(t, err) chat, err := chatStorage.GetChatByPartner(pub) require.Nil(t, err) diff --git a/chat/send_and_receive_func_test.go b/chat/send_and_receive_func_test.go index cd6476a..7f389c9 100644 --- a/chat/send_and_receive_func_test.go +++ b/chat/send_and_receive_func_test.go @@ -241,7 +241,8 @@ func TestChatBetweenAliceAndBob(t *testing.T) { require.Nil(t, err) // persist private message for bob - require.Nil(t, alice.chatStorage.CreateChat(bobIDKey)) + _, err = alice.chatStorage.CreateChat(bobIDKey) + require.Nil(t, err) bobChat, err := alice.chatStorage.GetChatByPartner(bobIDKey) require.Nil(t, err) require.NotNil(t, bobChat) From c51ede52d1f6671d081210a58bf2e4ad8fd3b7e3 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 25 Sep 2018 20:04:53 -0700 Subject: [PATCH 23/38] [chat] fixed group chat tests --- chat/receive_message.go | 12 +++++++----- chat/send_and_receive_func_test.go | 7 ++----- db/chat_storage.go | 20 +++++++------------- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/chat/receive_message.go b/chat/receive_message.go index dac08f3..df75c6b 100644 --- a/chat/receive_message.go +++ b/chat/receive_message.go @@ -299,12 +299,12 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { // convert plain protobuf message to database message dbMessage, err := protoPlainMsgToMessage(&plainMsg) - dbMessage.Sender = sender - dbMessage.Status = db.StatusPersisted - dbMessage.Received = true if err != nil { return err } + dbMessage.Sender = sender + dbMessage.Status = db.StatusPersisted + dbMessage.Received = true if dbMessage.AddUserToChat != nil { @@ -316,7 +316,7 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { // when the group chat doesn't exist we need to create it if groupChat == nil { - return c.chatStorage.CreateGroupChatFromMsg(dbMessage.AddUserToChat) + return c.chatStorage.CreateGroupChatFromMsg(dbMessage) } return nil @@ -391,9 +391,11 @@ func (c *Chat) handleReceivedMessage(msg *bpb.ChatMessage) error { return err } + // @todo add handle of new user + // when the group chat doesn't exist we need to create it if groupChat == nil { - return c.chatStorage.CreateGroupChatFromMsg(dbMessage.AddUserToChat) + return c.chatStorage.CreateGroupChatFromMsg(dbMessage) } return nil diff --git a/chat/send_and_receive_func_test.go b/chat/send_and_receive_func_test.go index 7f389c9..c27ae06 100644 --- a/chat/send_and_receive_func_test.go +++ b/chat/send_and_receive_func_test.go @@ -12,8 +12,6 @@ import ( uiapi "github.com/Bit-Nation/panthalassa/uiapi" bpb "github.com/Bit-Nation/protobuffers" require "github.com/stretchr/testify/require" - // log "gx/ipfs/QmTG23dvpBCBjqQwyDxV8CQT6jmS4PSftNr1VqHhE3MLy7/go-log" - "fmt" ed25519 "golang.org/x/crypto/ed25519" ) @@ -470,9 +468,6 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { if msg.Received { - // make sure group id is ok - // require.Equal(t, hex.EncodeToString(remoteGroupChatID), hex.EncodeToString(msgEv.Chat.GroupChatRemoteID)) - fmt.Println("got message") // make sure message is as we expect it to be require.Equal(t, "Greeting @all", string(msg.Message)) require.Equal(t, hex.EncodeToString(bobIDKey), hex.EncodeToString(msg.Sender)) @@ -523,6 +518,8 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { case <-done: return + case <-time.After(time.Second * 6): + require.FailNow(t, "timed out") } } diff --git a/db/chat_storage.go b/db/chat_storage.go index 64c0097..53a05fa 100644 --- a/db/chat_storage.go +++ b/db/chat_storage.go @@ -285,7 +285,7 @@ type ChatStorage interface { // returned int is the chat ID CreateChat(partner ed25519.PublicKey) (int, error) CreateGroupChat(partners []ed25519.PublicKey) (int, error) - CreateGroupChatFromMsg(createMessage *AddUserToChat) error + CreateGroupChatFromMsg(createMessage Message) error AddListener(func(e MessagePersistedEvent)) AllChats() ([]Chat, error) // set state of chat to unread messages @@ -305,23 +305,17 @@ type BoltChatStorage struct { km *km.KeyManager } -func (s *BoltChatStorage) CreateGroupChatFromMsg(createMessage *AddUserToChat) error { +func (s *BoltChatStorage) CreateGroupChatFromMsg(msg Message) error { - // add our self to the users - ourIDKeyStr, err := s.km.IdentityPublicKey() - if err != nil { - return err - } - ourIDKeyHex, err := hex.DecodeString(ourIDKeyStr) - if err != nil { - return err + if msg.AddUserToChat == nil { + return errors.New("can't create a chat from a message without the information needed to create it") } - createMessage.Users = append(createMessage.Users, ourIDKeyHex) + msg.AddUserToChat.Users = append(msg.AddUserToChat.Users, msg.Sender) c := Chat{ - Partners: createMessage.Users, - GroupChatRemoteID: createMessage.ChatID, + Partners: msg.AddUserToChat.Users, + GroupChatRemoteID: msg.AddUserToChat.ChatID, } return s.db.Save(&c) From 3288de05b994626a66109e78289b8e4b0f1b73f9 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 25 Sep 2018 22:19:50 -0700 Subject: [PATCH 24/38] [chat] fixed tests added group name --- Gopkg.toml | 2 +- chat.go | 4 ++-- chat/group_chat.go | 11 +++++++++-- chat/send_and_receive_func_test.go | 4 +++- chat/send_message.go | 7 ++++++- chat/utils.go | 1 + dapp/module/message/message_test.go | 3 ++- db/chat_storage.go | 18 +++++++++++++----- db/chat_storage_test.go | 3 ++- 9 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Gopkg.toml b/Gopkg.toml index 914b9ea..5ac7e35 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -138,4 +138,4 @@ [[constraint]] name = "github.com/Bit-Nation/protobuffers" - revision = "d9946ea4c0fa569249294c8645bdca0151a17fd6" + revision = "b104bab4e16e94443febee60f003a2e5bacd6e03" diff --git a/chat.go b/chat.go index 4c6f349..e959a21 100644 --- a/chat.go +++ b/chat.go @@ -65,7 +65,7 @@ func CreatePrivateChat(partnerStr string) (int, error) { } // return chatID -func CreateGroupChat(users string) (int, error) { +func CreateGroupChat(users string, name string) (int, error) { // make sure panthalassa has been started if panthalassaInstance == nil { @@ -88,7 +88,7 @@ func CreateGroupChat(users string) (int, error) { partners = append(partners, rawPartner) } - return panthalassaInstance.chat.CreateGroupChat(partners) + return panthalassaInstance.chat.CreateGroupChat(partners, name) } diff --git a/chat/group_chat.go b/chat/group_chat.go index fe04329..1627bd8 100644 --- a/chat/group_chat.go +++ b/chat/group_chat.go @@ -6,6 +6,7 @@ import ( "time" db "github.com/Bit-Nation/panthalassa/db" + uid "github.com/satori/go.uuid" ed25519 "golang.org/x/crypto/ed25519" ) @@ -68,10 +69,10 @@ func (c *Chat) AddUserToGroupChat(partners []ed25519.PublicKey, chatID int) erro } -func (c *Chat) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { +func (c *Chat) CreateGroupChat(partners []ed25519.PublicKey, name string) (int, error) { // create chat - chatID, err := c.chatStorage.CreateGroupChat(partners) + chatID, err := c.chatStorage.CreateGroupChat(partners, name) if err != nil { return 0, err } @@ -115,6 +116,11 @@ func (c *Chat) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { return 0, errors.New("chat with partner should exist at this point in time") } + msgID, err := uid.NewV4() + if err != nil { + return 0, err + } + // persist message msg := db.Message{ AddUserToChat: &db.AddUserToChat{ @@ -126,6 +132,7 @@ func (c *Chat) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { Status: db.StatusPersisted, Sender: idKey, GroupChatID: groupChat.GroupChatRemoteID, + ID: msgID.String(), } if err := partnerChat.PersistMessage(msg); err != nil { return 0, err diff --git a/chat/send_and_receive_func_test.go b/chat/send_and_receive_func_test.go index c27ae06..4ce5e53 100644 --- a/chat/send_and_receive_func_test.go +++ b/chat/send_and_receive_func_test.go @@ -452,7 +452,7 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { require.Nil(t, err) - groupChatID, err := alice.CreateGroupChat([]ed25519.PublicKey{bobIDKey}) + groupChatID, err := alice.CreateGroupChat([]ed25519.PublicKey{bobIDKey}, "Group between alice and bob") require.Nil(t, err) require.Nil(t, alice.SaveMessage(groupChatID, []byte("hi @all"))) @@ -470,6 +470,7 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { // make sure message is as we expect it to be require.Equal(t, "Greeting @all", string(msg.Message)) + require.Equal(t, "Group between alice and bob", msgEv.Chat.Name) require.Equal(t, hex.EncodeToString(bobIDKey), hex.EncodeToString(msg.Sender)) require.Equal(t, uint(1), msg.Version) require.Equal(t, db.StatusPersisted, msg.Status) @@ -500,6 +501,7 @@ func TestGroupChatBetweenAliceAndBob(t *testing.T) { // make sure the messages is as we expect it to be require.Equal(t, "hi @all", string(msg.Message)) + require.Equal(t, "Group between alice and bob", msgEv.Chat.Name) require.True(t, msg.Received) require.Equal(t, db.StatusPersisted, msg.Status) require.Equal(t, uint(1), msg.Version) diff --git a/chat/send_message.go b/chat/send_message.go index 25d6f4d..cb3bc86 100644 --- a/chat/send_message.go +++ b/chat/send_message.go @@ -37,6 +37,10 @@ func (c *Chat) SendMessage(receiver ed25519.PublicKey, dbMessage db.Message) err // attach add user data if dbMessage.AddUserToChat != nil { addUserMsg := dbMessage.AddUserToChat + groupChat, err := c.chatStorage.GetGroupChatByRemoteID(dbMessage.GroupChatID) + if err != nil { + return err + } plainMessage.AddUserPrivChat = &bpb.PlainChatMessage_AddUserPrivGroupChat{ Users: func() [][]byte { users := [][]byte{} @@ -45,7 +49,8 @@ func (c *Chat) SendMessage(receiver ed25519.PublicKey, dbMessage db.Message) err } return users }(), - ChatID: addUserMsg.ChatID, + ChatID: addUserMsg.ChatID, + GroupName: groupChat.Name, } } diff --git a/chat/utils.go b/chat/utils.go index 6790d4e..8804608 100644 --- a/chat/utils.go +++ b/chat/utils.go @@ -179,6 +179,7 @@ func protoPlainMsgToMessage(msg *bpb.PlainChatMessage) (db.Message, error) { for _, user := range msg.AddUserPrivChat.Users { m.AddUserToChat.Users = append(m.AddUserToChat.Users, user) } + m.AddUserToChat.ChatName = msg.AddUserPrivChat.GroupName } if isDAppMessage(msg) { diff --git a/dapp/module/message/message_test.go b/dapp/module/message/message_test.go index e67a301..71f0649 100644 --- a/dapp/module/message/message_test.go +++ b/dapp/module/message/message_test.go @@ -96,7 +96,8 @@ func TestPersistMessageSuccessfully(t *testing.T) { closer <- struct{}{} }) // create chat - require.Nil(t, chatStorage.CreateChat(chatPubKey)) + _, err = chatStorage.CreateChat(chatPubKey) + require.Nil(t, err) msgModule := New(chatStorage, dAppPubKey, nil) require.Nil(t, msgModule.Register(vm)) diff --git a/db/chat_storage.go b/db/chat_storage.go index 53a05fa..baacb44 100644 --- a/db/chat_storage.go +++ b/db/chat_storage.go @@ -38,6 +38,10 @@ var statuses = map[Status]bool{ // validate a given message var ValidMessage = func(m Message) error { + if m.ID == "" { + return errors.New("invalid message id (empty string)") + } + // validate version if m.Version == 0 { return errors.New("invalid version - got 0") @@ -87,8 +91,9 @@ type DAppMessage struct { } type AddUserToChat struct { - Users []ed25519.PublicKey - ChatID []byte + Users []ed25519.PublicKey + ChatName string + ChatID []byte } type Message struct { @@ -111,7 +116,8 @@ type Message struct { } type Chat struct { - ID int `storm:"id,increment"` + ID int `storm:"id,increment"` + Name string // partner will only be filled if this is a private chat Partner ed25519.PublicKey `storm:"index,unique"` Partners []ed25519.PublicKey @@ -284,7 +290,7 @@ type ChatStorage interface { GetGroupChatByRemoteID(id []byte) (*Chat, error) // returned int is the chat ID CreateChat(partner ed25519.PublicKey) (int, error) - CreateGroupChat(partners []ed25519.PublicKey) (int, error) + CreateGroupChat(partners []ed25519.PublicKey, name string) (int, error) CreateGroupChatFromMsg(createMessage Message) error AddListener(func(e MessagePersistedEvent)) AllChats() ([]Chat, error) @@ -314,6 +320,7 @@ func (s *BoltChatStorage) CreateGroupChatFromMsg(msg Message) error { msg.AddUserToChat.Users = append(msg.AddUserToChat.Users, msg.Sender) c := Chat{ + Name: msg.AddUserToChat.ChatName, Partners: msg.AddUserToChat.Users, GroupChatRemoteID: msg.AddUserToChat.ChatID, } @@ -434,7 +441,7 @@ func (s *BoltChatStorage) AllChats() ([]Chat, error) { return *chats, s.db.All(chats) } -func (s *BoltChatStorage) CreateGroupChat(partners []ed25519.PublicKey) (int, error) { +func (s *BoltChatStorage) CreateGroupChat(partners []ed25519.PublicKey, name string) (int, error) { // remote id ri := make([]byte, 200) @@ -449,6 +456,7 @@ func (s *BoltChatStorage) CreateGroupChat(partners []ed25519.PublicKey) (int, er } c := &Chat{ + Name: name, Partners: partners, GroupChatRemoteID: ri, } diff --git a/db/chat_storage_test.go b/db/chat_storage_test.go index 7c994b0..a0bcb60 100644 --- a/db/chat_storage_test.go +++ b/db/chat_storage_test.go @@ -97,7 +97,8 @@ func TestChatMessages(t *testing.T) { chatStor := NewChatStorage(storm, []func(e MessagePersistedEvent){}, km) // create chat - require.Nil(t, chatStor.CreateChat(partner)) + _, err = chatStor.CreateChat(partner) + require.Nil(t, err) chat, err := chatStor.GetChatByPartner(partner) require.Nil(t, err) require.NotNil(t, chat) From f3b2ffd36a9b2975719cd9cd418b1bb897642d85 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 25 Sep 2018 22:28:26 -0700 Subject: [PATCH 25/38] [chat] renamed chat name to group chat name --- chat.go | 1 + db/chat_storage.go | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/chat.go b/chat.go index e959a21..c042494 100644 --- a/chat.go +++ b/chat.go @@ -109,6 +109,7 @@ func AllChats() (string, error) { chatsRep = append(chatsRep, map[string]interface{}{ "chat_id": chat.ID, "unread_messages": chat.UnreadMessages, + "group_chat_name": chat.GroupChatName, }) } diff --git a/db/chat_storage.go b/db/chat_storage.go index baacb44..8b4ccda 100644 --- a/db/chat_storage.go +++ b/db/chat_storage.go @@ -116,8 +116,8 @@ type Message struct { } type Chat struct { - ID int `storm:"id,increment"` - Name string + ID int `storm:"id,increment"` + GroupChatName string // partner will only be filled if this is a private chat Partner ed25519.PublicKey `storm:"index,unique"` Partners []ed25519.PublicKey @@ -320,7 +320,7 @@ func (s *BoltChatStorage) CreateGroupChatFromMsg(msg Message) error { msg.AddUserToChat.Users = append(msg.AddUserToChat.Users, msg.Sender) c := Chat{ - Name: msg.AddUserToChat.ChatName, + GroupChatName: msg.AddUserToChat.ChatName, Partners: msg.AddUserToChat.Users, GroupChatRemoteID: msg.AddUserToChat.ChatID, } @@ -456,7 +456,7 @@ func (s *BoltChatStorage) CreateGroupChat(partners []ed25519.PublicKey, name str } c := &Chat{ - Name: name, + GroupChatName: name, Partners: partners, GroupChatRemoteID: ri, } From 7c48539c4bfec4085f53348ddd6ecef68d69f9e1 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Tue, 25 Sep 2018 22:33:57 -0700 Subject: [PATCH 26/38] [panthalassa] added chat_partner and partners to chat --- chat.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chat.go b/chat.go index c042494..9922319 100644 --- a/chat.go +++ b/chat.go @@ -108,8 +108,10 @@ func AllChats() (string, error) { for _, chat := range chats { chatsRep = append(chatsRep, map[string]interface{}{ "chat_id": chat.ID, + "chat_partner": chat.Partner, "unread_messages": chat.UnreadMessages, "group_chat_name": chat.GroupChatName, + "partners": chat.Partners, }) } From 92be238f77e508d6f397dc56e40805922d59c0c2 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Wed, 26 Sep 2018 10:00:05 -0700 Subject: [PATCH 27/38] [ios] fixed compile error --- Gopkg.lock | 17 ++--------------- chat/send_message.go | 2 +- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 3b5b1c8..7e4c727 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -4,7 +4,7 @@ [[projects]] name = "github.com/Bit-Nation/protobuffers" packages = ["."] - revision = "a71cefee1ec2dda6f720cacaa1b3217b1589e33c" + revision = "b104bab4e16e94443febee60f003a2e5bacd6e03" [[projects]] branch = "master" @@ -34,19 +34,6 @@ ] revision = "5312a61534124124185d41f09206b9fef1d88403" -[[projects]] - name = "github.com/asdine/storm" - packages = [ - ".", - "codec", - "codec/json", - "index", - "internal", - "q" - ] - revision = "5a6fe65e3993f63951c8e3f64c812536c9e23595" - version = "v2.1.2" - [[projects]] branch = "master" name = "github.com/aristanetworks/goarista" @@ -782,6 +769,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "470d40dd4b96cf5aca7d1710b5dcf5bea1be9e20be5860b8530a9824997a99b9" + inputs-digest = "105a127428276ed3fe782aae284c0b9b32a3d3eaa9cbaeadb2194f3d5a71142c" solver-name = "gps-cdcl" solver-version = 1 diff --git a/chat/send_message.go b/chat/send_message.go index cb3bc86..9029295 100644 --- a/chat/send_message.go +++ b/chat/send_message.go @@ -50,7 +50,7 @@ func (c *Chat) SendMessage(receiver ed25519.PublicKey, dbMessage db.Message) err return users }(), ChatID: addUserMsg.ChatID, - GroupName: groupChat.Name, + GroupName: groupChat.GroupChatName, } } From 3b672a6c2160ef5a1f9a45bf0a9158fe45cf579a Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Wed, 26 Sep 2018 11:23:27 -0700 Subject: [PATCH 28/38] [chat] added sender to ui events --- chat/handler.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chat/handler.go b/chat/handler.go index 893722d..12e0b4a 100644 --- a/chat/handler.go +++ b/chat/handler.go @@ -143,6 +143,7 @@ func (c *Chat) handlePersistedMessage(e db.MessagePersistedEvent) { "chat": e.Chat.ID, "received": e.Message.Received, "dapp": dapp, + "sender": e.Message.Sender, }) } @@ -154,6 +155,7 @@ func (c *Chat) handlePersistedMessage(e db.MessagePersistedEvent) { "chat": e.Chat.ID, "received": e.Message.Received, "dapp": dapp, + "sender": e.Message.Sender, }) } @@ -165,6 +167,7 @@ func (c *Chat) handlePersistedMessage(e db.MessagePersistedEvent) { "chat": e.Chat.ID, "received": e.Message.Received, "dapp": dapp, + "sender": e.Message.Sender, }) } From b936d95ddb7dcdeb74771115625a2f573f0b34e2 Mon Sep 17 00:00:00 2001 From: Borjan Trajanoski Date: Thu, 27 Sep 2018 10:05:54 +0200 Subject: [PATCH 29/38] [vm] Temporarily brought back otto as a VM --- bip32/bip32_test.go | 8 +- dapp/dapp.go | 24 +- dapp/dapp_storage_test.go | 2 +- dapp/module/callbacks/module.go | 104 ++++---- dapp/module/callbacks/module_test.go | 194 +++++++------- dapp/module/db/db.go | 237 +++++++++--------- dapp/module/db/db_test.go | 58 ++--- dapp/module/ethAddress/module.go | 8 +- dapp/module/ethAddress/module_test.go | 10 +- dapp/module/logger/module.go | 33 ++- dapp/module/logger/module_test.go | 19 +- dapp/module/message/message.go | 143 ++++++----- dapp/module/message/message_test.go | 109 +------- dapp/module/message/test_utils.js.go | 49 ++++ dapp/module/modal/module.go | 120 ++++----- dapp/module/modal/module_test.go | 88 +++---- dapp/module/module.go | 4 +- dapp/module/randBytes/module.go | 69 ++--- dapp/module/randBytes/module_test.go | 21 +- dapp/module/renderer/dapp/module.go | 73 +++--- dapp/module/renderer/dapp/module_test.go | 73 ++---- dapp/module/renderer/message/module.go | 68 +++-- dapp/module/renderer/message/module_test.go | 61 ++--- dapp/module/sendEthTx/module.go | 98 +++----- dapp/module/sendEthTx/module_test.go | 44 ++-- dapp/module/uuidv4/module.go | 38 +-- dapp/module/uuidv4/module_test.go | 33 ++- dapp/request_limitation/count_throttling.go | 11 +- .../count_throttling_test.go | 71 +++--- dapp/request_limitation/throttling.go | 11 +- dapp/request_limitation/throttling_test.go | 6 +- dapp/validator/call.go | 32 +-- dapp/validator/object.go | 68 +++-- dapp/validator/object_test.go | 22 +- db/bolt_to_storm.go | 2 +- db/migration.go | 2 +- db/migration_test.go | 2 +- db/test_utils.go | 9 +- mobile_interface.go | 2 +- queue/test_utils.go | 3 +- 40 files changed, 974 insertions(+), 1055 deletions(-) create mode 100644 dapp/module/message/test_utils.js.go diff --git a/bip32/bip32_test.go b/bip32/bip32_test.go index 223c6c5..3bd6422 100644 --- a/bip32/bip32_test.go +++ b/bip32/bip32_test.go @@ -132,10 +132,10 @@ func TestKeyDerivation(t *testing.T) { //Test vector set one testVectorErrorMapping := map[string]int{ - "m/0H/1": 1, - "m/0H/1/2H": 1, - "m/0H/1/2H/2": 1, - "m/0H/1/2H/2/1000000000": 1, + "m/0H/1": 1, + "m/0H/1/2H": 1, + "m/0H/1/2H/2": 1, + "m/0H/1/2H/2/1000000000": 1, "m/0": 0, "m/0/2147483647H": 0, "m/0/2147483647H/1": 0, diff --git a/dapp/dapp.go b/dapp/dapp.go index 637fdea..d7dd68d 100644 --- a/dapp/dapp.go +++ b/dapp/dapp.go @@ -14,13 +14,13 @@ import ( storm "github.com/asdine/storm" log "github.com/ipfs/go-log" logger "github.com/op/go-logging" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) var sysLog = log.Logger("dapp") type DApp struct { - vm *duktape.Context + vm *otto.Otto logger *logger.Logger app *Data // will be called when the app shut down @@ -34,14 +34,15 @@ type DApp struct { // close DApp func (d *DApp) Close() { - defer d.vm.DestroyHeap() - d.logger.Info(fmt.Sprintf("shutting down: %s (%s)", hex.EncodeToString(d.app.UsedSigningKey), d.app.Name)) - for _, mod := range d.vmModules { - if err := mod.Close(); err != nil { - sysLog.Error(err) + d.vm.Interrupt <- func() { + d.logger.Info(fmt.Sprintf("shutting down: %s (%s)", hex.EncodeToString(d.app.UsedSigningKey), d.app.Name)) + for _, mod := range d.vmModules { + if err := mod.Close(); err != nil { + sysLog.Error(err) + } } + d.closeChan <- d.app } - d.closeChan <- d.app } func (d *DApp) ID() string { @@ -73,7 +74,8 @@ func New(l *logger.Logger, app *Data, vmModules []module.Module, closer chan<- * } // create VM - vm := duktape.New() + vm := otto.New() + vm.Interrupt = make(chan func(), 1) // register all vm modules for _, m := range vmModules { @@ -130,8 +132,7 @@ func New(l *logger.Logger, app *Data, vmModules []module.Module, closer chan<- * // start the DApp async go func() { - // Synonymous to vm.Run in Otto - err := vm.PevalString(string(app.Code)) + _, err := vm.Run(app.Code) if err != nil { l.Errorf(err.Error()) } @@ -146,6 +147,7 @@ func New(l *logger.Logger, app *Data, vmModules []module.Module, closer chan<- * } return dApp, nil case <-time.After(timeOut): + vm.Interrupt <- func() {} closer <- app return nil, errors.New("timeout - failed to start DApp") } diff --git a/dapp/dapp_storage_test.go b/dapp/dapp_storage_test.go index f750d43..f8bb40a 100644 --- a/dapp/dapp_storage_test.go +++ b/dapp/dapp_storage_test.go @@ -11,8 +11,8 @@ import ( uiApi "github.com/Bit-Nation/panthalassa/uiapi" storm "github.com/asdine/storm" - bolt "github.com/coreos/bbolt" require "github.com/stretchr/testify/require" + bolt "go.etcd.io/bbolt" ed25519 "golang.org/x/crypto/ed25519" ) diff --git a/dapp/module/callbacks/module.go b/dapp/module/callbacks/module.go index f102ca3..ab50a36 100644 --- a/dapp/module/callbacks/module.go +++ b/dapp/module/callbacks/module.go @@ -8,7 +8,7 @@ import ( validator "github.com/Bit-Nation/panthalassa/dapp/validator" log "github.com/ipfs/go-log" logger "github.com/op/go-logging" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) var debugger = log.Logger("callbacks") @@ -34,7 +34,7 @@ func New(l *logger.Logger) *Module { var count uint - functions := map[uint]*duktape.Context{} + functions := map[uint]*otto.Value{} cbChans := map[*chan error]bool{} for { @@ -110,7 +110,7 @@ func New(l *logger.Logger) *Module { } type addFunction struct { - fn *duktape.Context + fn *otto.Value respChan chan struct { id uint error error @@ -119,12 +119,12 @@ type addFunction struct { type fetchFunction struct { id uint - respChan chan *duktape.Context + respChan chan *otto.Value } type Module struct { logger *logger.Logger - vm *duktape.Context + vm *otto.Otto reqLim *reqLim.Count addFunctionChan chan addFunction fetchFunctionChan chan fetchFunction @@ -146,33 +146,37 @@ func (m *Module) Close() error { // e.g. myRegisteredFunction(payloadObj, cb) // the callback must be called in order to "return" from the function func (m *Module) CallFunction(id uint, payload string) error { + debugger.Debug(fmt.Errorf("call function with id: %d and payload: %s", id, payload)) - respChan := make(chan *duktape.Context) + respChan := make(chan *otto.Value) m.fetchFunctionChan <- fetchFunction{ id: id, respChan: respChan, } - vm := <-respChan + fn := <-respChan - if vm == nil || vm.GetType(0).IsNone() { + if fn == nil { return errors.New(fmt.Sprintf("function with id: %d does not exist", id)) } // check if function is registered - if !vm.IsFunction(0) { + if !fn.IsFunction() { return errors.New(fmt.Sprintf("function with id: %d does not exist", id)) } // parse params - objArgs := "(" + payload + ")" + objArgs, err := m.vm.Object("(" + payload + ")") + if err != nil { + return err + } done := make(chan error, 1) m.addCBChan <- &done alreadyCalled := false - _, err := vm.PushGlobalGoFunction("callbackCallFunction", func(context *duktape.Context) int { + _, err = fn.Call(*fn, objArgs, func(call otto.FunctionCall) otto.Value { defer func() { m.rmCBChan <- &done @@ -181,43 +185,26 @@ func (m *Module) CallFunction(id uint, payload string) error { // check if callback has already been called if alreadyCalled { m.logger.Error("Already called callback") - if context.IsFunction(1) { - context.PushString("Callback: Already called callback") - context.Call(1) - } - return 1 + return m.vm.MakeCustomError("Callback", "Already called callback") } alreadyCalled = true - if !context.IsUndefined(0) { - firstParameter := context.ToString(0) - if context.IsFunction(1) { - context.PushString(firstParameter) - context.Call(1) - } - done <- errors.New(firstParameter) - return 1 + // check parameters + err := call.Argument(0) + + if !err.IsUndefined() { + done <- errors.New(err.String()) + return otto.Value{} } done <- nil - return 0 + return otto.Value{} }) if err != nil { m.logger.Error(err.Error()) } - // Push objArgs to the stack as first parameter - err = vm.PevalString(objArgs) - if err != nil { - m.logger.Error(err.Error()) - } - // Push callbackCallFunction to the stack as second parameter - err = vm.PevalString(`callbackCallFunction`) - if err != nil { - m.logger.Error(err.Error()) - } - // Use 2 when calling as we just pushed 2 parameters to the stack - vm.Call(2) + return <-done } @@ -228,17 +215,20 @@ func (m *Module) CallFunction(id uint, payload string) error { // a registered function will be called with an object containing information // and a callback that should be called (with an optional error) in order to // "return" -func (m *Module) Register(vm *duktape.Context) error { +func (m *Module) Register(vm *otto.Otto) error { m.vm = vm - _, err := vm.PushGlobalGoFunction("registerFunction", func(context *duktape.Context) int { + err := vm.Set("registerFunction", func(call otto.FunctionCall) otto.Value { // validate function call v := validator.New() v.Set(0, &validator.TypeFunction) - if err := v.Validate(context); err != nil { - m.logger.Error(fmt.Sprintf(`registerFunction needs a callback as it's first param %s`, err.Error())) - return 1 + if err := v.Validate(vm, call); err != nil { + m.logger.Error(fmt.Sprintf(`registerFunction needs a callback as it's first param %s`, err.String())) + return *err } + // callback + fn := call.Argument(0) + // add function to stack idRespChan := make(chan struct { id uint @@ -246,7 +236,7 @@ func (m *Module) Register(vm *duktape.Context) error { }, 1) m.addFunctionChan <- addFunction{ respChan: idRespChan, - fn: context, + fn: &fn, } // response addResp := <-idRespChan @@ -254,11 +244,14 @@ func (m *Module) Register(vm *duktape.Context) error { // exit vm on error if addResp.error != nil { m.logger.Error(addResp.error.Error()) - return 1 + return otto.Value{} } - // convert function id to int - functionId := int(addResp.id) + // convert function id to otto value + functionId, err := otto.ToValue(addResp.id) + if err != nil { + m.logger.Error(err.Error()) + } return functionId @@ -267,22 +260,27 @@ func (m *Module) Register(vm *duktape.Context) error { return err } - _, err = vm.PushGlobalGoFunction("unRegisterFunction", func(context *duktape.Context) int { + return vm.Set("unRegisterFunction", func(call otto.FunctionCall) otto.Value { // validate function call v := validator.New() v.Set(0, &validator.TypeNumber) - if err := v.Validate(context); err != nil { - return 1 + if err := v.Validate(vm, call); err != nil { + return *err } // function id - funcID := context.ToInt(0) + funcID := call.Argument(0) + id, err := funcID.ToInteger() + if err != nil { + m.logger.Error(err.Error()) + return otto.Value{} + } // delete function from channel - m.deleteFunctionChan <- uint(funcID) + m.deleteFunctionChan <- uint(id) - return 0 + return otto.Value{} }) - return err + } diff --git a/dapp/module/callbacks/module_test.go b/dapp/module/callbacks/module_test.go index 708fcd9..c8569a6 100644 --- a/dapp/module/callbacks/module_test.go +++ b/dapp/module/callbacks/module_test.go @@ -1,37 +1,35 @@ package callbacks import ( - "strconv" "testing" "time" log "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) func TestFuncRegistration(t *testing.T) { m := New(nil) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) require.Equal(t, uint(0), m.reqLim.Count()) - funcId, err := vm.PushGlobalGoFunction("callbackTestFuncRegistration", func(context *duktape.Context) int { - return 0 + funcId, err := vm.Call(`registerFunction`, vm, func(call otto.FunctionCall) otto.Value { + return otto.Value{} }) require.Nil(t, err) - err = vm.PevalString(`registerFunction(callbackTestFuncRegistration)`) - require.Nil(t, err) require.Equal(t, uint(1), m.reqLim.Count()) - id := funcId - require.Equal(t, int(1), id) + id, err := funcId.ToInteger() + require.Nil(t, err) + require.Equal(t, int64(1), id) // fetch function and assert - respChan := make(chan *duktape.Context) + respChan := make(chan *otto.Value) m.fetchFunctionChan <- fetchFunction{ id: 1, respChan: respChan, @@ -43,22 +41,22 @@ func TestFuncRegistration(t *testing.T) { func TestFuncUnRegisterSuccess(t *testing.T) { m := New(nil) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) // register function - funcId, err := vm.PushGlobalGoFunction("callbackTestFuncUnRegisterSuccess", func(context *duktape.Context) int { - return 0 + funcId, err := vm.Call(`registerFunction`, vm, func(call otto.FunctionCall) otto.Value { + return otto.Value{} }) require.Nil(t, err) - err = vm.PevalString(`registerFunction(callbackTestFuncUnRegisterSuccess)`) - require.Nil(t, err) + // make sure the id is the one we expect it to be - id := funcId - require.Equal(t, int(1), id) + id, err := funcId.ToInteger() + require.Nil(t, err) + require.Equal(t, int64(1), id) // make sure function exist - respChan := make(chan *duktape.Context) + respChan := make(chan *otto.Value) m.fetchFunctionChan <- fetchFunction{ id: 1, respChan: respChan, @@ -67,15 +65,21 @@ func TestFuncUnRegisterSuccess(t *testing.T) { require.Equal(t, uint(1), m.reqLim.Count()) // un-register function that has never been registered - err = vm.PevalString(`unRegisterFunction(23565)`) + returnedValue, err := vm.Call(`unRegisterFunction`, vm, 23565) + require.Nil(t, err) + returnedValueStr, err := returnedValue.ToString() require.Nil(t, err) + require.Equal(t, "undefined", returnedValueStr) // request limitation must still be one since function that have not been registered // can't decrease the counter require.Equal(t, uint(1), m.reqLim.Count()) // successfully un-register function - err = vm.PevalString(`unRegisterFunction(` + strconv.Itoa(id) + `)`) + returnedValue, err = vm.Call(`unRegisterFunction`, vm, id) require.Nil(t, err) + returnedValueStr, err = returnedValue.ToString() + require.Nil(t, err) + require.Equal(t, "undefined", returnedValueStr) // wait for the go routine to sync up time.Sleep(time.Millisecond * 100) // should be 0 since the the function id we passed in exists @@ -86,40 +90,37 @@ func TestFuncUnRegisterSuccess(t *testing.T) { func TestFuncCallSuccess(t *testing.T) { m := New(nil) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackTestFuncCallSuccess", func(context *duktape.Context) int { + _, err := vm.Call(`registerFunction`, vm, func(call otto.FunctionCall) otto.Value { - if !context.IsObject(0) { - panic("callbackTestFuncCallSuccess : 0 is not an object") - } - if !context.GetPropString(0, "key") { - panic("callbackTestFuncCallSuccess : key missing") + valueFromObj, err := call.Argument(0).Object().Get("key") + if err != nil { + panic(err) } - valueFromObj := context.ToString(-1) - context.Pop() - if valueFromObj != "value" { + if valueFromObj.String() != "value" { panic("expected value of key to be: value") } - if !context.IsFunction(1) { + cb := call.Argument(1) + + if !cb.IsFunction() { panic("expected second argument to be a callback") } - context.PushUndefined() - context.Call(1) + _, err = cb.Call(cb) + if err != nil { + m.logger.Error(err.Error()) + } - return 0 + return otto.Value{} }) require.Nil(t, err) - err = vm.PevalString(`registerFunction(callbackTestFuncCallSuccess)`) - require.Nil(t, err) - // make sure function exist - respChan := make(chan *duktape.Context) + respChan := make(chan *otto.Value) m.fetchFunctionChan <- fetchFunction{ id: 1, respChan: respChan, @@ -134,40 +135,39 @@ func TestFuncCallError(t *testing.T) { m := New(nil) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackTestFuncCallError", func(context *duktape.Context) int { + _, err := vm.Call(`registerFunction`, vm, func(call otto.FunctionCall) otto.Value { - if !context.IsObject(0) { - panic("callbackTestFuncCallSuccess : 0 is not an object") - } - if !context.GetPropString(0, "key") { - panic("callbackTestFuncCallSuccess : key missing") + valueFromObj, err := call.Argument(0).Object().Get("key") + if err != nil { + panic(err) } - valueFromObj := context.ToString(-1) - if valueFromObj != "value" { + if valueFromObj.String() != "value" { panic("expected value of key to be: value") } - if !context.IsFunction(1) { + cb := call.Argument(1) + + if !cb.IsFunction() { panic("expected second argument to be a callback") } - context.Pop() - context.PushString("I am an error") - context.Call(1) + _, err = cb.Call(cb, "I am an error") - return 0 + if err != nil { + m.logger.Error(err.Error()) + } + + return otto.Value{} }) require.Nil(t, err) - err = vm.PevalString(`registerFunction(callbackTestFuncCallError)`) - require.Nil(t, err) // make sure function exist - respChan := make(chan *duktape.Context) + respChan := make(chan *otto.Value) m.fetchFunctionChan <- fetchFunction{ id: 1, respChan: respChan, @@ -182,81 +182,64 @@ func TestFuncCallBackTwice(t *testing.T) { m := New(log.MustGetLogger("")) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackTestFuncCallBackTwiceTestUndefined", func(context *duktape.Context) int { - if !context.IsUndefined(0) { - panic("expected value to be undefined") - } - return 0 - }) - require.Nil(t, err) - _, err = vm.PushGlobalGoFunction("callbackTestFuncCallBackTwiceTestAlreadyCalled", func(context *duktape.Context) int { - if !context.IsString(0) { - panic("expected value to be string") - } - if context.ToString(0) != "Callback: Already called callback" { - panic("Expected an error that tells me that I alrady called the callback") - } - return 0 - }) - require.Nil(t, err) - - _, err = vm.PushGlobalGoFunction("callbackTestFuncCallBackTwice", func(context *duktape.Context) int { + _, err := vm.Call(`registerFunction`, vm, func(call otto.FunctionCall) otto.Value { - if !context.IsObject(0) { - panic("callbackTestFuncCallSuccess : 0 is not an object") - } - if !context.GetPropString(0, "key") { - panic("callbackTestFuncCallSuccess : key missing") + valueFromObj, err := call.Argument(0).Object().Get("key") + if err != nil { + panic(err) } - valueFromObj := context.ToString(-1) - - if valueFromObj != "value" { + if valueFromObj.String() != "value" { panic("expected value of key to be: value") } - if !context.IsFunction(1) { + cb := call.Argument(1) + + if !cb.IsFunction() { panic("expected second argument to be a callback") } - context.Pop() - context.DupTop() - context.PushUndefined() - context.PevalString(`callbackTestFuncCallBackTwiceTestUndefined`) - context.Call(2) - context.Pop() - context.PushUndefined() - context.PevalString(`callbackTestFuncCallBackTwiceTestAlreadyCalled`) - context.Call(2) + val, err := cb.Call(cb) + if err != nil { + panic(err) + } + if !val.IsUndefined() { + panic("expected value to be undefined") + } - return 0 + val, err = cb.Call(cb) + if err != nil { + panic(err) + } + if val.String() != "Callback: Already called callback" { + panic("Expected an error that tells me that I alrady called the callback") + } + + return otto.Value{} }) require.Nil(t, err) - err = vm.PevalString(`registerFunction(callbackTestFuncCallBackTwice)`) - require.Nil(t, err) // make sure function exist - respChan := make(chan *duktape.Context) + respChan := make(chan *otto.Value) m.fetchFunctionChan <- fetchFunction{ id: 1, respChan: respChan, } require.NotNil(t, <-respChan) - err = m.CallFunction(1, `{key: "value"}`) - require.Nil(t, err) + m.CallFunction(1, `{key: "value"}`) } func TestModule_CallFunctionThatIsNotRegistered(t *testing.T) { m := New(log.MustGetLogger("")) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) err := m.CallFunction(1, "{}") @@ -267,19 +250,16 @@ func TestModule_CallFunctionThatIsNotRegistered(t *testing.T) { func TestModule_Close(t *testing.T) { m := New(log.MustGetLogger("")) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackTestModuleClose", func(context *duktape.Context) int { + // register function + _, err := vm.Call("registerFunction", vm, func(call otto.FunctionCall) otto.Value { m.Close() - return 0 + return otto.Value{} }) require.Nil(t, err) - // register function - err = vm.PevalString(`registerFunction(callbackTestModuleClose)`) - require.Nil(t, err) - require.EqualError(t, m.CallFunction(1, "{}"), "closed application") } diff --git a/dapp/module/db/db.go b/dapp/module/db/db.go index 533b3e6..c48c6f4 100644 --- a/dapp/module/db/db.go +++ b/dapp/module/db/db.go @@ -3,14 +3,13 @@ package db import ( "encoding/json" "errors" - "fmt" "time" reqLim "github.com/Bit-Nation/panthalassa/dapp/request_limitation" validator "github.com/Bit-Nation/panthalassa/dapp/validator" log "github.com/ipfs/go-log" opLogger "github.com/op/go-logging" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) var logger = log.Logger("db module") @@ -33,149 +32,155 @@ func (m *Module) Close() error { return nil } -func (m *Module) Register(vm *duktape.Context) error { +func (m *Module) Register(vm *otto.Otto) error { - var itemsToPopBeforeCallback int - handleError := func(errMsg string, context *duktape.Context, position int) int { - if context.IsFunction(position) { - context.PopN(itemsToPopBeforeCallback) - context.PushString(errMsg) - context.Call(1) - return 0 + handleError := func(errMsg string, cb otto.Value) otto.Value { + if cb.IsFunction() { + _, err := cb.Call(cb, errMsg) + if err != nil { + m.logger.Error(errMsg) + } + return otto.Value{} } logger.Error(errMsg) - return 1 + return otto.Value{} } - _, err := vm.PushGlobalGoFunction("dbPut", func(context *duktape.Context) int { - logger.Debug("put value") + return vm.Set("db", map[string]interface{}{ + "put": func(call otto.FunctionCall) otto.Value { - // validate call - v := validator.New() - v.Set(0, &validator.TypeString) - v.Set(2, &validator.TypeFunction) - if err := v.Validate(context); err != nil { - return handleError(err.Error(), context, 2) - } + logger.Debug("put value") - // fetch key and value - key := context.ToString(0) - value := context.ToString(1) - // marshal value into json - byteValue, err := json.Marshal(value) - if err != nil { - return handleError(err.Error(), context, 2) - } + // validate call + v := validator.New() + v.Set(0, &validator.TypeString) + v.Set(2, &validator.TypeFunction) + cb := call.Argument(2) + if err := v.Validate(vm, call); err != nil { + return handleError(err.String(), cb) + } - throttlingFunc := func(dec chan struct{}, vmDone chan struct{}) { - defer func() { - <-vmDone - }() - // persist key and value - if err := m.dAppDB.Put([]byte(key), byteValue); err != nil { - dec <- struct{}{} - handleError(err.Error(), context, 2) + // fetch key and value + key := call.Argument(0) + value, err := call.Argument(1).Export() + if err != nil { + return handleError(err.Error(), cb) } - dec <- struct{}{} - // call callback - context.PopN(itemsToPopBeforeCallback) - context.PushUndefined() - context.Call(1) - } - m.reqLim.Exec(throttlingFunc) - return 0 + // marshal value into json + byteValue, err := json.Marshal(value) + if err != nil { + return handleError(err.Error(), cb) + } - }) + m.reqLim.Exec(func(dec chan struct{}) { - _, err = vm.PushGlobalGoFunction("dbHas", func(context *duktape.Context) int { - //@TODO figure out why logger.Errorf instead of logger.Debug - logger.Errorf("check if value exist") + // persist key and value + if err := m.dAppDB.Put([]byte(key.String()), byteValue); err != nil { + dec <- struct{}{} + handleError(err.Error(), cb) + } + dec <- struct{}{} + // call callback + _, err = cb.Call(cb) + if err != nil { + logger.Error(err.Error()) + } - // validate function call - v := validator.New() - v.Set(0, &validator.TypeString) - v.Set(1, &validator.TypeFunction) + }) - if err := v.Validate(context); err != nil { - return handleError(err.Error(), context, 1) - } + return otto.Value{} - // key of database - key := context.ToString(0) + }, + "has": func(call otto.FunctionCall) otto.Value { - // check if database has value - has, err := m.dAppDB.Has([]byte(key)) - if err != nil { - return handleError(err.Error(), context, 1) - } - context.PopN(itemsToPopBeforeCallback) - context.PushUndefined() - context.PushBoolean(has) - context.Call(2) - return 0 - }) + logger.Errorf("check if value exist") - _, err = vm.PushGlobalGoFunction("dbGet", func(context *duktape.Context) int { - m.logger.Debug("get value") + // validate function call + v := validator.New() + v.Set(0, &validator.TypeString) + v.Set(1, &validator.TypeFunction) + cb := call.Argument(1) + if err := v.Validate(vm, call); err != nil { + return handleError(err.String(), cb) + } - // validate function call - v := validator.New() - v.Set(0, &validator.TypeString) - v.Set(1, &validator.TypeFunction) + // key of database + key := call.Argument(0).String() - if err := v.Validate(context); err != nil { - return handleError(err.Error(), context, 1) - } + // check if database has value + has, err := m.dAppDB.Has([]byte(key)) + if err != nil { + return handleError(err.Error(), cb) + } + _, err = cb.Call(cb, nil, has) + if err != nil { + m.logger.Error(err.Error()) + } + return otto.Value{} - // key of database - key := context.ToString(0) + }, + "get": func(call otto.FunctionCall) otto.Value { - // raw value of key - value, err := m.dAppDB.Get([]byte(key)) - if err != nil { - return handleError(err.Error(), context, 1) - } + m.logger.Debug("get value") - // unmarshal json - var unmarshalledValue interface{} - if err := json.Unmarshal(value, &unmarshalledValue); err != nil { - return handleError(err.Error(), context, 1) - } + // validate function call + v := validator.New() + v.Set(0, &validator.TypeString) + v.Set(1, &validator.TypeFunction) + cb := call.Argument(1) + if err := v.Validate(vm, call); err != nil { + return handleError(err.String(), cb) + } - // call callback with error - context.PopN(itemsToPopBeforeCallback) - context.PushUndefined() - context.PushString(fmt.Sprint(unmarshalledValue)) - context.Call(2) - return 0 - }) + // key of database + key := call.Argument(0).String() - _, err = vm.PushGlobalGoFunction("dbDelete", func(context *duktape.Context) int { + // raw value of key + value, err := m.dAppDB.Get([]byte(key)) + if err != nil { + return handleError(err.Error(), cb) + } - logger.Debug("delete value") + // unmarshal json + var unmarshalledValue interface{} + if err := json.Unmarshal(value, &unmarshalledValue); err != nil { + return handleError(err.Error(), cb) + } - // validate function call - v := validator.New() - v.Set(0, &validator.TypeString) - v.Set(1, &validator.TypeFunction) + // call callback with error + _, err = cb.Call(cb, nil, unmarshalledValue) + if err != nil { + m.logger.Error(err.Error()) + } + return otto.Value{} - if err := v.Validate(context); err != nil { - return handleError(err.Error(), context, 1) - } + }, + "delete": func(call otto.FunctionCall) otto.Value { - // delete value - key := context.ToString(0) - if err := m.dAppDB.Delete([]byte(key)); err != nil { - return handleError(err.Error(), context, 1) - } + logger.Debug("delete value") - context.PopN(itemsToPopBeforeCallback) - context.PushUndefined() - context.Call(1) - return 0 + // validate function call + v := validator.New() + v.Set(0, &validator.TypeString) + v.Set(1, &validator.TypeFunction) + cb := call.Argument(1) + if err := v.Validate(vm, call); err != nil { + return handleError(err.String(), cb) + } - }) + // delete value + key := call.Argument(0) + if err := m.dAppDB.Delete([]byte(key.String())); err != nil { + return handleError(err.Error(), cb) + } - return err + if _, err := cb.Call(cb); err != nil { + logger.Error(err.Error()) + } + + return otto.Value{} + + }, + }) } diff --git a/dapp/module/db/db_test.go b/dapp/module/db/db_test.go index b2d9306..0b50ea2 100644 --- a/dapp/module/db/db_test.go +++ b/dapp/module/db/db_test.go @@ -6,8 +6,8 @@ import ( "time" log "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) type inMemoryDB struct { @@ -40,22 +40,19 @@ func TestModulePut(t *testing.T) { storage: map[string][]byte{}, }, log.MustGetLogger("")) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) closer := make(chan struct{}, 1) - _, err := vm.PushGlobalGoFunction("callbackDbPut", func(context *duktape.Context) int { - errBool := !context.IsUndefined(0) - require.False(t, errBool) + vm.Call("db.put", vm, "key", "value", func(call otto.FunctionCall) otto.Value { + err := call.Argument(0) + require.False(t, err.IsDefined()) closer <- struct{}{} - return 0 + return otto.Value{} }) - require.Nil(t, err) - - vm.PevalString(`dbPut("key","value",callbackDbPut)`) select { case <-closer: @@ -75,26 +72,24 @@ func TestModuleHas(t *testing.T) { }, } - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) closer := make(chan struct{}, 1) + vm.Call("db.has", vm, "key", func(call otto.FunctionCall) otto.Value { - _, err := vm.PushGlobalGoFunction("callbackDbHas", func(context *duktape.Context) int { - errBool := !context.IsUndefined(0) - require.False(t, errBool) + err := call.Argument(0) + require.False(t, err.IsDefined()) - exist := context.IsBoolean(1) + exist, e := call.Argument(1).ToBoolean() + require.Nil(t, e) require.True(t, exist) closer <- struct{}{} - return 0 + return otto.Value{} }) - require.Nil(t, err) - - vm.PevalString(`dbHas("key",callbackDbHas)`) select { case <-closer: @@ -118,26 +113,24 @@ func TestModuleGet(t *testing.T) { logger: log.MustGetLogger(""), } - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) closer := make(chan struct{}, 1) - _, err = vm.PushGlobalGoFunction("callbackDbGet", func(context *duktape.Context) int { + vm.Call("db.get", vm, "key", func(call otto.FunctionCall) otto.Value { - errBool := !context.IsUndefined(0) - require.False(t, errBool) + err := call.Argument(0) + require.False(t, err.IsDefined()) - value := context.ToString(1) + value := call.Argument(1).String() require.Equal(t, "value", value) closer <- struct{}{} - return 0 + return otto.Value{} }) - require.Nil(t, err) - vm.PevalString(`dbGet("key",callbackDbGet)`) select { case <-closer: case <-time.After(time.Second * 2): @@ -159,24 +152,21 @@ func TestModuleDelete(t *testing.T) { }, } - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) closer := make(chan struct{}, 1) + vm.Call("db.delete", vm, "key", func(call otto.FunctionCall) otto.Value { - _, err = vm.PushGlobalGoFunction("callbackDbDelete", func(context *duktape.Context) int { - - errBool := !context.IsUndefined(0) - require.False(t, errBool) + err := call.Argument(0) + require.False(t, err.IsDefined()) closer <- struct{}{} - return 0 + return otto.Value{} }) - vm.PevalString(`dbDelete("key", callbackDbDelete)`) - select { case <-closer: case <-time.After(time.Second * 2): diff --git a/dapp/module/ethAddress/module.go b/dapp/module/ethAddress/module.go index 34daf8e..a96295b 100644 --- a/dapp/module/ethAddress/module.go +++ b/dapp/module/ethAddress/module.go @@ -3,7 +3,7 @@ package ethAddress import ( keyManager "github.com/Bit-Nation/panthalassa/keyManager" log "github.com/ipfs/go-log" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) var logger = log.Logger("eth address") @@ -22,7 +22,7 @@ func (m *Module) Close() error { return nil } -func (m *Module) Register(context *duktape.Context) error { +func (m *Module) Register(vm *otto.Otto) error { logger.Debug("get ethereum address") @@ -30,7 +30,7 @@ func (m *Module) Register(context *duktape.Context) error { if err != nil { return err } - context.PushString(addr) - return err + + return vm.Set("ethereumAddress", addr) } diff --git a/dapp/module/ethAddress/module_test.go b/dapp/module/ethAddress/module_test.go index 4e3315b..3af85dd 100644 --- a/dapp/module/ethAddress/module_test.go +++ b/dapp/module/ethAddress/module_test.go @@ -6,8 +6,8 @@ import ( keyManager "github.com/Bit-Nation/panthalassa/keyManager" keyStore "github.com/Bit-Nation/panthalassa/keyStore" mnemonic "github.com/Bit-Nation/panthalassa/mnemonic" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) func TestModule_Register(t *testing.T) { @@ -26,11 +26,13 @@ func TestModule_Register(t *testing.T) { // create address module mod := New(km) - vm := duktape.New() + vm := otto.New() mod.Register(vm) - v := vm.ToString(0) - require.Equal(t, "0x748A6536dE0a8b1902f808233DD75ec4451cdFC6", v) + v, err := vm.Run(`ethereumAddress`) + require.Nil(t, err) + + require.Equal(t, "0x748A6536dE0a8b1902f808233DD75ec4451cdFC6", v.String()) } diff --git a/dapp/module/logger/module.go b/dapp/module/logger/module.go index 97639f4..76b3152 100644 --- a/dapp/module/logger/module.go +++ b/dapp/module/logger/module.go @@ -7,7 +7,7 @@ import ( log "github.com/ipfs/go-log" net "github.com/libp2p/go-libp2p-net" logger "github.com/op/go-logging" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) var sysLog = log.Logger("logger module logger") @@ -60,22 +60,21 @@ func (l *Logger) Close() error { // Register a module that writes console.log // to the given logger -func (l *Logger) Register(vm *duktape.Context) error { - //@TODO Find a way to overwrite method console.log if neccessary, so that we don't need to call consoleLog - _, err := vm.PushGlobalGoFunction("consoleLog", func(context *duktape.Context) int { - sysLog.Debug("write log statement") - toLog := []string{} - var i int - for { - if context.GetType(i).IsNone() { - break +func (l *Logger) Register(vm *otto.Otto) error { + + return vm.Set("console", map[string]interface{}{ + "log": func(call otto.FunctionCall) otto.Value { + + sysLog.Debug("write log statement") + + toLog := []string{} + for _, arg := range call.ArgumentList { + sysLog.Debug("log: ", toLog) + toLog = append(toLog, arg.String()) } - sysLog.Debug("log: ", toLog) - toLog = append(toLog, context.ToString(i)) - i++ - } - l.Logger.Info(strings.Join(toLog, ",")) - return 0 + l.Logger.Info(strings.Join(toLog, ",")) + return otto.Value{} + }, }) - return err + } diff --git a/dapp/module/logger/module_test.go b/dapp/module/logger/module_test.go index 20eff0f..fed6272 100644 --- a/dapp/module/logger/module_test.go +++ b/dapp/module/logger/module_test.go @@ -4,8 +4,8 @@ import ( "testing" logger "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) type testValue struct { @@ -24,22 +24,21 @@ func (w testWriter) Write(b []byte) (int, error) { func TestLoggerModule(t *testing.T) { - //@TODO Find a way to overwrite method console.log if neccessary, so that we don't need to call consoleLog testValues := []testValue{ testValue{ - js: `consoleLog(1, 2, 3)`, + js: `console.log(1, 2, 3)`, assertion: func(consoleOut string) { require.Equal(t, "1,2,3\n", consoleOut) }, }, testValue{ - js: `consoleLog("hi","there")`, + js: `console.log("hi","there")`, assertion: func(consoleOut string) { require.Equal(t, "hi,there\n", consoleOut) }, }, testValue{ - js: `consoleLog({key: 4})`, + js: `console.log({key: 4})`, assertion: func(consoleOut string) { require.Equal(t, "[object Object]\n", consoleOut) }, @@ -47,14 +46,14 @@ func TestLoggerModule(t *testing.T) { testValue{ js: ` var cb = function(){}; - consoleLog(cb) + console.log(cb) `, assertion: func(consoleOut string) { - require.Equal(t, "function () { [ecmascript code] }\n", consoleOut) + require.Equal(t, "function(){}\n", consoleOut) }, }, testValue{ - js: `consoleLog("hi",1)`, + js: `console.log("hi",1)`, assertion: func(consoleOut string) { require.Equal(t, "hi,1\n", consoleOut) }, @@ -64,7 +63,7 @@ func TestLoggerModule(t *testing.T) { for _, testValue := range testValues { // create VM - vm := duktape.New() + vm := otto.New() // create logger b := logger.NewLogBackend(testWriter{ @@ -79,7 +78,7 @@ func TestLoggerModule(t *testing.T) { loggerModule.Logger = l loggerModule.Register(vm) - err = vm.PevalString((testValue.js)) + _, err = vm.Run(testValue.js) require.Nil(t, err) } diff --git a/dapp/module/message/message.go b/dapp/module/message/message.go index f88f1b7..1ccfbfa 100644 --- a/dapp/module/message/message.go +++ b/dapp/module/message/message.go @@ -6,14 +6,15 @@ import ( "errors" "time" + log "github.com/ipfs/go-log" + ed25519 "golang.org/x/crypto/ed25519" + reqLim "github.com/Bit-Nation/panthalassa/dapp/request_limitation" validator "github.com/Bit-Nation/panthalassa/dapp/validator" db "github.com/Bit-Nation/panthalassa/db" - log "github.com/ipfs/go-log" logger "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" uuid "github.com/satori/go.uuid" - ed25519 "golang.org/x/crypto/ed25519" - duktape "gopkg.in/olebedev/go-duktape.v3" ) type Module struct { @@ -47,9 +48,9 @@ func (m *Module) Close() error { return nil } -func (m *Module) Register(vm *duktape.Context) error { - _, err := vm.PushGlobalGoFunction("sendMessage", func(context *duktape.Context) int { - var itemsToPopBeforeCallback int +func (m *Module) Register(vm *otto.Otto) error { + return vm.Set("sendMessage", func(call otto.FunctionCall) otto.Value { + sysLog.Debug("send message") // validate function call v := validator.New() @@ -59,27 +60,32 @@ func (m *Module) Register(vm *duktape.Context) error { v.Set(1, &validator.TypeObject) // callback v.Set(2, &validator.TypeFunction) + cb := call.Argument(2) // utils to handle an occurred error - handleError := func(errMsg string) int { - if context.IsFunction(2) { - context.PopN(itemsToPopBeforeCallback) - context.PushString(errMsg) - context.Call(1) - return 0 + handleError := func(errMsg string) otto.Value { + if cb.IsFunction() { + _, err := cb.Call(cb, errMsg) + if err != nil { + m.logger.Error(err.Error()) + } + return otto.Value{} } m.logger.Error(errMsg) - return 1 + return otto.Value{} } - if err := v.Validate(vm); err != nil { + if err := v.Validate(vm, call); err != nil { // in the case an callback has been passed we want to call it with the error - return handleError(err.Error()) + return handleError(err.String()) } + + messagePayload := call.Argument(1).Object() + objv := validator.NewObjValidator() objv.Set("shouldSend", validator.ObjTypeBool, true) objv.Set("params", validator.ObjTypeObject, false) objv.Set("type", validator.ObjTypeString, false) - if err := objv.Validate(vm, 1); err != nil { - return handleError(err.Error()) + if err := objv.Validate(vm, *messagePayload); err != nil { + return handleError(err.String()) } dAppMessage := db.DAppMessage{ @@ -88,8 +94,7 @@ func (m *Module) Register(vm *duktape.Context) error { } // chat in which the message should be persisted - chatStr := context.ToString(0) - itemsToPopBeforeCallback++ + chatStr := call.Argument(0).String() chat, err := hex.DecodeString(chatStr) if err != nil { return handleError(err.Error()) @@ -97,53 +102,65 @@ func (m *Module) Register(vm *duktape.Context) error { if len(chat) != 32 { return handleError("chat must be 32 bytes long") } + // should this message be sent or kept locally? - if !context.GetPropString(1, "shouldSend") { - handleError(`key "shouldSend" doesn't exist`) + shouldSendVal, err := messagePayload.Get("shouldSend") + if err != nil { + return handleError(err.Error()) } - dAppMessage.ShouldSend = context.ToBoolean(-1) - itemsToPopBeforeCallback++ - itemsToPopBeforeCallback++ + dAppMessage.ShouldSend, err = shouldSendVal.ToBoolean() + if err != nil { + return handleError(err.Error()) + } + // set optional type of the message - if !context.GetPropString(1, "type") { - handleError(`key "type" doesn't exist`) + if hasKey(messagePayload.Keys(), "type") { + msgType, err := messagePayload.Get("type") + if err != nil { + return handleError(err.Error()) + } + dAppMessage.Type = msgType.String() } - dAppMessage.Type = context.ToString(-1) - itemsToPopBeforeCallback++ - itemsToPopBeforeCallback++ + // set optional params - if !context.GetPropString(1, "params") { - handleError(`key "params" doesn't exist`) - } + if hasKey(messagePayload.Keys(), "params") { - //@TODO Find a way to iterate over nested object key / values - //@TODO Lets pass objects to VM in json format and handle them fully in golang as it's much more powerful? - //@TODO Figure out if Duktape has a way to iterate over object keys and values - if !context.GetPropString(-1, "key") { - handleError(`key "key" doesn't exist`) - } + // fetch params object + paramsObj, err := messagePayload.Get("params") + if err != nil { + return handleError(err.Error()) + } + params := paramsObj.Object() + + // transform params to map + for _, objKey := range params.Keys() { + vmValue, err := params.Get(objKey) + value, err := vmValue.Export() + if err != nil { + return handleError(err.Error()) + } + dAppMessage.Params[objKey] = value + } - vmValue := context.ToString(-1) - itemsToPopBeforeCallback++ - itemsToPopBeforeCallback++ - dAppMessage.Params["key"] = vmValue - // marshal params - marshaledParams, err := json.Marshal(dAppMessage.Params) - if err != nil { - return handleError(err.Error()) - } + // marshal params + marshaledParams, err := json.Marshal(dAppMessage.Params) + if err != nil { + return handleError(err.Error()) + } + + // make sure it's less than 64 KB + if len(marshaledParams) > 64*1024 { + return handleError("the message params can't be bigger than 64 kb") + } + if err := json.Unmarshal(marshaledParams, &dAppMessage.Params); err != nil { + return handleError(err.Error()) + } - // make sure it's less than 64 KB - if len(marshaledParams) > 64*1024 { - return handleError("the message params can't be bigger than 64 kb") - } - if err := json.Unmarshal(marshaledParams, &dAppMessage.Params); err != nil { - return handleError(err.Error()) } - throttlingFunc := func(dec chan struct{}, vmDone chan struct{}) { + // persist message + m.reqLim.Exec(func(dec chan struct{}) { defer func() { - <-vmDone dec <- struct{}{} }() @@ -175,18 +192,12 @@ func (m *Module) Register(vm *duktape.Context) error { handleError(err.Error()) return } + if _, err := cb.Call(cb); err != nil { + m.logger.Error(err.Error()) + } + }) - // See https://duktape.org/api.html - // Each function description includes Stack : (No effect on value stack) or a description of the effect it has on the stack - // When we call functions which modify the stack, we need to Pop them in order for things to work as intended - context.PopN(itemsToPopBeforeCallback) - context.PushUndefined() - context.Call(1) - return - } - m.reqLim.Exec(throttlingFunc) - return 0 + return otto.Value{} }) - return err } diff --git a/dapp/module/message/message_test.go b/dapp/module/message/message_test.go index bdbd6c5..6497078 100644 --- a/dapp/module/message/message_test.go +++ b/dapp/module/message/message_test.go @@ -9,14 +9,15 @@ import ( "testing" "time" + ed25519 "golang.org/x/crypto/ed25519" + db "github.com/Bit-Nation/panthalassa/db" km "github.com/Bit-Nation/panthalassa/keyManager" ks "github.com/Bit-Nation/panthalassa/keyStore" mnemonic "github.com/Bit-Nation/panthalassa/mnemonic" storm "github.com/asdine/storm" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - ed25519 "golang.org/x/crypto/ed25519" - duktape "gopkg.in/olebedev/go-duktape.v3" ) func createStorm() *storm.DB { @@ -49,7 +50,7 @@ func createKeyManager() *km.KeyManager { func TestPersistMessageSuccessfully(t *testing.T) { - vm := duktape.New() + vm := otto.New() // dapp pub key dAppPubKey, _, err := ed25519.GenerateKey(rand.Reader) @@ -101,112 +102,26 @@ func TestPersistMessageSuccessfully(t *testing.T) { msgModule := New(chatStorage, dAppPubKey, nil) require.Nil(t, msgModule.Register(vm)) - msg := `({ + msg := map[string]interface{}{ "shouldSend": true, - "params": { + "params": map[string]interface{}{ "key": "value", }, "type": "SEND_MONEY", - })` - - _, err = vm.PushGlobalGoFunction("callbackSendMessage", func(context *duktape.Context) int { - if !context.IsUndefined(0) { - require.Fail(t, context.ToString(0)) - } - - return 0 - }) - require.Nil(t, err) - vm.PevalString(`sendMessage(` + `"` + hex.EncodeToString(chatPubKey) + `"` + `,` + msg + `,` + `callbackSendMessage)`) - select { - case <-closer: - case <-time.After(time.Second * 5): - require.Fail(t, "timed out") } -} - -func TestPersistInvalidFunctionCall(t *testing.T) { - - vm := duktape.New() - - // dapp pub key - dAppPubKey, _, err := ed25519.GenerateKey(rand.Reader) - require.Nil(t, err) - - // chat pub key - chatPubKey, _, err := ed25519.GenerateKey(rand.Reader) - require.Nil(t, err) - - msgModule := New(nil, dAppPubKey, nil) - require.Nil(t, msgModule.Register(vm)) - - closer := make(chan struct{}, 1) - - _, err = vm.PushGlobalGoFunction("callbackSendMessage", func(context *duktape.Context) int { + vm.Call("sendMessage", vm, hex.EncodeToString(chatPubKey), msg, func(call otto.FunctionCall) otto.Value { - err := context.ToString(0) - require.Equal(t, "ValidationError: expected parameter 1 to be of type object", err) - closer <- struct{}{} - return 0 - }) - require.Nil(t, err) - vm.PevalString(`sendMessage(` + `"` + hex.EncodeToString(chatPubKey) + `"` + `,` + `"nil"` + `,` + `callbackSendMessage)`) - select { - case <-closer: - case <-time.After(time.Second): - require.Fail(t, "timed out") - } - -} - -// test whats happening if the chat is too short -func TestPersistChatTooShort(t *testing.T) { - - vm := duktape.New() - - msgModule := New(nil, nil, nil) - require.Nil(t, msgModule.Register(vm)) - - closer := make(chan struct{}, 1) - - _, err := vm.PushGlobalGoFunction("callbackSendMessage", func(context *duktape.Context) int { - err := context.ToString(0) - require.Equal(t, "chat must be 32 bytes long", err) + err := call.Argument(0) + if err.IsDefined() { + require.Fail(t, err.String()) + } closer <- struct{}{} - return 0 - + return otto.Value{} }) - require.Nil(t, err) - vm.PevalString(`sendMessage(` + `"` + hex.EncodeToString(make([]byte, 16)) + `"` + `,` + `({"shouldSend": true})` + `,` + `callbackSendMessage)`) - select { - case <-closer: - case <-time.After(time.Second): - require.Fail(t, "timed out") - } - -} - -// test what happens if we try to send without -func TestPersistWithoutShouldSend(t *testing.T) { - - vm := duktape.New() - msgModule := New(nil, nil, nil) - require.Nil(t, msgModule.Register(vm)) - - closer := make(chan struct{}, 1) - - _, err := vm.PushGlobalGoFunction("callbackSendMessage", func(context *duktape.Context) int { - err := context.ToString(0) - require.Equal(t, "ValidationError: Missing value for required key: shouldSend", err) - closer <- struct{}{} - return 0 - }) - require.Nil(t, err) - vm.PevalString(`sendMessage(` + `"` + hex.EncodeToString(make([]byte, 16)) + `"` + `,` + `({})` + `,` + `callbackSendMessage)`) select { case <-closer: case <-time.After(time.Second): diff --git a/dapp/module/message/test_utils.js.go b/dapp/module/message/test_utils.js.go new file mode 100644 index 0000000..89f8dd3 --- /dev/null +++ b/dapp/module/message/test_utils.js.go @@ -0,0 +1,49 @@ +package message + +import ( + db "github.com/Bit-Nation/panthalassa/db" + ed25519 "golang.org/x/crypto/ed25519" +) + +type testMessageStorage struct { + persistMessageToSend func(to ed25519.PublicKey, msg db.Message) error + persistReceivedMessage func(partner ed25519.PublicKey, msg db.Message) error + updateStatus func(partner ed25519.PublicKey, msgID int64, newStatus db.Status) error + messages func(partner ed25519.PublicKey, start int64, amount uint) ([]db.Message, error) + allChats func() ([]ed25519.PublicKey, error) + addListener func(fn func(e db.MessagePersistedEvent)) + getMessage func(partner ed25519.PublicKey, messageID int64) (*db.Message, error) + persistDAppMessage func(partner ed25519.PublicKey, msg db.DAppMessage) error +} + +func (s *testMessageStorage) PersistMessageToSend(partner ed25519.PublicKey, msg db.Message) error { + return s.persistMessageToSend(partner, msg) +} + +func (s *testMessageStorage) UpdateStatus(partner ed25519.PublicKey, msgID int64, newStatus db.Status) error { + return s.updateStatus(partner, msgID, newStatus) +} + +func (s *testMessageStorage) PersistReceivedMessage(partner ed25519.PublicKey, msg db.Message) error { + return s.persistReceivedMessage(partner, msg) +} + +func (s *testMessageStorage) Messages(partner ed25519.PublicKey, start int64, amount uint) ([]db.Message, error) { + return s.messages(partner, start, amount) +} + +func (s *testMessageStorage) AllChats() ([]ed25519.PublicKey, error) { + return s.allChats() +} + +func (s *testMessageStorage) AddListener(fn func(e db.MessagePersistedEvent)) { + s.addListener(fn) +} + +func (s *testMessageStorage) GetMessage(partner ed25519.PublicKey, messageID int64) (*db.Message, error) { + return s.getMessage(partner, messageID) +} + +func (s *testMessageStorage) PersistDAppMessage(partner ed25519.PublicKey, msg db.DAppMessage) error { + return s.persistDAppMessage(partner, msg) +} diff --git a/dapp/module/modal/module.go b/dapp/module/modal/module.go index da97c3f..a3d249d 100644 --- a/dapp/module/modal/module.go +++ b/dapp/module/modal/module.go @@ -5,14 +5,13 @@ import ( "fmt" "time" - log "github.com/ipfs/go-log" - ed25519 "golang.org/x/crypto/ed25519" - reqLim "github.com/Bit-Nation/panthalassa/dapp/request_limitation" validator "github.com/Bit-Nation/panthalassa/dapp/validator" + log "github.com/ipfs/go-log" logger "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" uuid "github.com/satori/go.uuid" - duktape "gopkg.in/olebedev/go-duktape.v3" + ed25519 "golang.org/x/crypto/ed25519" ) type Device interface { @@ -23,12 +22,12 @@ var sysLog = log.Logger("modal") type addModalID struct { id string - closer *duktape.Context + closer *otto.Value } type fetchModalCloser struct { id string - respChan chan *duktape.Context + respChan chan *otto.Value } type Module struct { @@ -57,7 +56,7 @@ func New(l *logger.Logger, device Device, dAppIDKey ed25519.PublicKey) *Module { go func() { - modals := map[string]*duktape.Context{} + modals := map[string]*otto.Value{} // exit if channels are closed if m.addModalIDChan == nil || m.fetchModalCloserChan == nil || m.deleteModalID == nil { @@ -101,9 +100,10 @@ func (m *Module) Close() error { // the second parameter should be the layout to render // and the third parameter is an optional callback that // will called with an optional error -func (m *Module) Register(vm *duktape.Context) error { +func (m *Module) Register(vm *otto.Otto) error { + + err := vm.Set("renderModal", func(call otto.FunctionCall) otto.Value { - _, err := vm.PushGlobalGoFunction("renderModal", func(context *duktape.Context) int { sysLog.Debug("render modal") // validate function call @@ -114,16 +114,19 @@ func (m *Module) Register(vm *duktape.Context) error { v.Set(1, &validator.TypeString) // callback v.Set(2, &validator.TypeFunction) - if err := v.Validate(context); err != nil { - m.logger.Error(err.Error()) - return 1 + if err := v.Validate(vm, call); err != nil { + m.logger.Error(err.String()) + return otto.Value{} } // modal ui id - uiID := context.ToString(0) + uiID := call.Argument(0).String() + + // callback + cb := call.Argument(2) // make sure ui id is registered - mIdChan := make(chan *duktape.Context) + mIdChan := make(chan *otto.Value) m.fetchModalCloserChan <- fetchModalCloser{ id: uiID, respChan: mIdChan, @@ -132,35 +135,37 @@ func (m *Module) Register(vm *duktape.Context) error { // a modal closer can only exist with relation to a modal ID. // So if the modal closer exist the modal id exist as well if modalCloser == nil { - errMsg := fmt.Sprintf("MissingModalID: modal UI ID: '%s' does not exist", uiID) - context.PushString(errMsg) - context.PushString(uiID) - context.Call(2) - return 1 + errMsg := fmt.Sprintf("modal UI ID: '%s' does not exist", uiID) + if _, err := cb.Call(cb, vm.MakeCustomError("MissingModalID", errMsg), uiID); err != nil { + m.logger.Error(errMsg) + } + return otto.Value{} } // get layout - layout := context.ToString(1) + layout := call.Argument(1).String() sysLog.Debugf("going to render: %s with UI id %s", layout, uiID) // execute show modal action in // context of request limitation - // @TODO figure out why concurrently using "go func" instead of "func" makes the vm/context lose the stack - func() { + go func() { // request to show modal if err := m.device.RenderModal(uiID, layout, m.dAppIDKey); err != nil { - context.PushString(`Error: failed to render modal ` + err.Error()) - context.Call(1) + _, err = cb.Call(cb, vm.MakeCustomError("Error", "failed to render modal")) + if err != nil { + m.logger.Error(err.Error()) + } return } - context.PushUndefined() - context.Call(1) + if _, err := cb.Call(cb); err != nil { + m.logger.Error(err.Error()) + } }() - return 0 + return otto.Value{} }) @@ -168,63 +173,62 @@ func (m *Module) Register(vm *duktape.Context) error { return err } - _, err = vm.PushGlobalGoFunction("newModalUIID", func(context *duktape.Context) int { + return vm.Set("newModalUIID", func(call otto.FunctionCall) otto.Value { + // validate function call v := validator.New() // close handler v.Set(0, &validator.TypeFunction) // callback v.Set(1, &validator.TypeFunction) - if err := v.Validate(context); err != nil { - m.logger.Error(err.Error()) - return 1 + if err := v.Validate(vm, call); err != nil { + m.logger.Error(err.String()) + return otto.Value{} } + cb := call.Argument(1) + // create new id id, err := uuid.NewV4() if err != nil { - context.PushString("Error " + err.Error()) - context.Call(1) - return 1 + _, err = cb.Call(cb, vm.MakeCustomError("Error", err.Error())) + if err != nil { + m.logger.Error(err.Error()) + } + return otto.Value{} } // increase request limitation counter - throttlingFunc := func(dec chan struct{}, vmDone chan struct{}) { - defer func() { - <-vmDone - }() + m.modalIDsReqLim.Exec(func(dec chan struct{}) { + // add ui id & closer to stack + closer := call.Argument(0) m.addModalIDChan <- addModalID{ id: id.String(), - closer: context, + closer: &closer, } // call callback - context.PopN(0) - context.PushUndefined() - context.PushString(id.String()) - context.Call(2) - - //@TODO find a way to determine if the callback errored out - //if err != nil { - // in the case of an error we would like to remove the id - // and decrease our request limitation - // m.deleteModalID <- id.String() - // m.logger.Error(err.Error()) - //} - } - m.modalIDsReqLim.Exec(throttlingFunc) - return 0 + _, err = cb.Call(cb, nil, id.String()) + if err != nil { + // in the case of an error we would like to remove the id + // and decrease our request limitation + m.deleteModalID <- id.String() + m.logger.Error(err.Error()) + } + }) + + return otto.Value{} }) - return err + } // close the modal func (m *Module) CloseModal(uiID string) { // fetch closer - respChan := make(chan *duktape.Context) + respChan := make(chan *otto.Value) m.fetchModalCloserChan <- fetchModalCloser{ id: uiID, respChan: respChan, @@ -235,7 +239,9 @@ func (m *Module) CloseModal(uiID string) { } // close modal - closer.Call(0) + if _, err := closer.Call(*closer); err != nil { + m.logger.Error(err.Error()) + } // finish close (decrease counter & delete from id's") m.deleteModalID <- uiID diff --git a/dapp/module/modal/module_test.go b/dapp/module/modal/module_test.go index 7a9b5dd..763007a 100644 --- a/dapp/module/modal/module_test.go +++ b/dapp/module/modal/module_test.go @@ -5,10 +5,10 @@ import ( "time" log "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" uuid "github.com/satori/go.uuid" require "github.com/stretchr/testify/require" ed25519 "golang.org/x/crypto/ed25519" - duktape "gopkg.in/olebedev/go-duktape.v3" ) type testDevice struct { @@ -24,45 +24,45 @@ func TestModule_CloseModal(t *testing.T) { // create modal module logger := log.MustGetLogger("") m := New(logger, nil, []byte("")) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) // closer closed := false - - _, err := vm.PushGlobalGoFunction("callbackCloserCloseModal", func(context *duktape.Context) int { + closer := func() { closed = true - return 0 - }) - require.Nil(t, err) + } closeTest := make(chan struct{}, 1) // create new uuid - _, err = vm.PushGlobalGoFunction("callbackTestModuleCloseModal", func(context *duktape.Context) int { + _, err := vm.Call("newModalUIID", vm, closer, func(call otto.FunctionCall) otto.Value { + // fetch callback data - errBool := context.IsUndefined(0) - modalID := context.ToString(1) + err := call.Argument(0) + modalID := call.Argument(1) // error must be undefined - require.True(t, errBool) + require.True(t, err.IsUndefined()) + // convert returned id to uuid - id, convertErr := uuid.FromString(modalID) + id, convertErr := uuid.FromString(modalID.String()) require.Nil(t, convertErr) - require.Equal(t, modalID, id.String()) + require.Equal(t, modalID.String(), id.String()) + // id must be registered in modal id map - respChan := make(chan *duktape.Context) + respChan := make(chan *otto.Value) m.fetchModalCloserChan <- fetchModalCloser{ id: id.String(), respChan: respChan, } require.NotNil(t, <-respChan) + // close modal - vm.PevalString(`callbackCloserCloseModal`) m.CloseModal(id.String()) // id must NOT be registered in modal id map - respChan = make(chan *duktape.Context) + respChan = make(chan *otto.Value) m.fetchModalCloserChan <- fetchModalCloser{ id: id.String(), respChan: respChan, @@ -72,11 +72,9 @@ func TestModule_CloseModal(t *testing.T) { // close test closeTest <- struct{}{} - return 0 + return otto.Value{} }) require.Nil(t, err) - err = vm.PevalString(`newModalUIID(callbackCloserCloseModal,callbackTestModuleCloseModal)`) - require.Nil(t, err) select { case <-closeTest: @@ -105,29 +103,29 @@ func TestModule_RenderModal(t *testing.T) { // create module logger := log.MustGetLogger("") m := New(logger, device, []byte("id pub key")) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) // we just register a fake it here to just // make sure that we have an ID in the vm m.addModalIDChan <- addModalID{ id: uiID, - closer: &duktape.Context{}, + closer: &otto.Value{}, } done := make(chan struct{}, 1) - _, err := vm.PushGlobalGoFunction("callbackTestModuleCloseModal", func(context *duktape.Context) int { + + _, err := vm.Call("renderModal", vm, uiID, "{jsx: 'tree'}", func(call otto.FunctionCall) otto.Value { + // make sure device has been called require.True(t, calledDevice) // close test done <- struct{}{} - return 0 + return otto.Value{} }) require.Nil(t, err) - err = vm.PevalString(`renderModal("` + uiID + `","{jsx: 'tree'}",callbackTestModuleCloseModal)`) - require.Nil(t, err) select { case <-done: @@ -142,19 +140,17 @@ func TestModal_RenderWithoutID(t *testing.T) { // create module logger := log.MustGetLogger("") m := New(logger, nil, []byte("id pub key")) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) done := make(chan struct{}, 1) - _, err := vm.PushGlobalGoFunction("callbackTestModalRenderWithoutID", func(context *duktape.Context) int { - err := context.ToString(0) - require.Equal(t, "MissingModalID: modal UI ID: 'id_do_not_exist' does not exist", err) + + vm.Call("renderModal", vm, "id_do_not_exist", "", func(call otto.FunctionCall) otto.Value { + err := call.Argument(0) + require.Equal(t, "MissingModalID: modal UI ID: 'id_do_not_exist' does not exist", err.String()) done <- struct{}{} - return 0 + return otto.Value{} }) - require.Nil(t, err) - err = vm.PevalString(`renderModal("id_do_not_exist", "", callbackTestModalRenderWithoutID)`) - require.Nil(t, err) select { case <-done: @@ -169,41 +165,39 @@ func TestModal_RequestLimitation(t *testing.T) { // create module logger := log.MustGetLogger("") m := New(logger, nil, []byte("id pub key")) - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackCloserRequestLimitation", func(context *duktape.Context) int { - return 0 - }) - require.Nil(t, err) + closer := func() otto.Value { + return otto.Value{} + } // make sure that current amount of registered ids is 0 require.Equal(t, uint(0), m.modalIDsReqLim.Current()) // closer done := make(chan struct{}, 1) - _, err = vm.PushGlobalGoFunction("callbackTestModalRequestLimitation", func(context *duktape.Context) int { + + vm.Call("newModalUIID", vm, closer, func(call otto.FunctionCall) otto.Value { + // newModalUIID must register a new id require.Equal(t, uint(1), m.modalIDsReqLim.Current()) // close modal with UI ID - id := context.ToString(1) - vm.PevalString(`callbackCloserRequestLimitation`) - m.CloseModal(id) + id := call.Argument(1) + m.CloseModal(id.String()) // wait a bit to sync go routines - time.Sleep(time.Millisecond * 100) + time.Sleep(time.Millisecond * 10) // make sure id was removed from current require.Equal(t, uint(0), m.modalIDsReqLim.Current()) done <- struct{}{} - return 0 + return otto.Value{} }) - require.Nil(t, err) - err = vm.PevalString(`newModalUIID(callbackCloserRequestLimitation,callbackTestModalRequestLimitation)`) - require.Nil(t, err) + select { case <-done: case <-time.After(time.Second * 3): diff --git a/dapp/module/module.go b/dapp/module/module.go index 5bbcb51..b24d093 100644 --- a/dapp/module/module.go +++ b/dapp/module/module.go @@ -1,10 +1,10 @@ package module import ( - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) type Module interface { - Register(vm *duktape.Context) error + Register(vm *otto.Otto) error Close() error } diff --git a/dapp/module/randBytes/module.go b/dapp/module/randBytes/module.go index 923d12b..8e269ce 100644 --- a/dapp/module/randBytes/module.go +++ b/dapp/module/randBytes/module.go @@ -2,13 +2,11 @@ package randBytes import ( "crypto/rand" - "fmt" - "strings" validator "github.com/Bit-Nation/panthalassa/dapp/validator" log "github.com/ipfs/go-log" logger "github.com/op/go-logging" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) var randSource = rand.Reader @@ -29,46 +27,53 @@ func (m *Module) Close() error { return nil } -func (m *Module) Register(vm *duktape.Context) error { - _, err := vm.PushGlobalGoFunction("randomBytes", func(context *duktape.Context) int { +func (m *Module) Register(vm *otto.Otto) error { + return vm.Set("randomBytes", func(call otto.FunctionCall) otto.Value { + sysLog.Debug("generate random bytes") - var itemsToPopBeforeCallback int + // validate call v := validator.New() v.Set(0, &validator.TypeNumber) v.Set(1, &validator.TypeFunction) - handleError := func(errMsg string) int { - if context.IsFunction(1) { - context.PopN(itemsToPopBeforeCallback) - context.PushString(errMsg) - context.Call(1) - return 0 - } - m.logger.Error(errMsg) - return 1 - } - if err := v.Validate(context); err != nil { - m.logger.Error(err.Error()) + if err := v.Validate(vm, call); err != nil { + m.logger.Error(err.String()) } + cb := call.Argument(1) + // convert to integer - amount := context.ToInt(0) + amount, err := call.Argument(0).ToInteger() + if err != nil { + _, err := cb.Call(cb, err.Error()) + if err != nil { + m.logger.Error(err.Error()) + } + return otto.Value{} + } + + // read random bytes destination := make([]byte, amount) - _, err := randSource.Read(destination) + _, err = randSource.Read(destination) if err != nil { - handleError(err.Error()) - return 1 - } // if err != nil { + _, err := cb.Call(cb, err.Error()) + if err != nil { + m.logger.Error(err.Error()) + } + return otto.Value{} + } // call callback - context.PopN(itemsToPopBeforeCallback) - context.PushUndefined() - byteString := fmt.Sprint(destination) - jsFriendlyString := strings.Replace(strings.TrimSuffix(strings.TrimPrefix(byteString, "["), "]"), " ", ", ", -1) - context.PushString(jsFriendlyString) - context.Call(2) - return 0 - }) + _, err = cb.Call(cb, nil, destination) + if err != nil { + _, err := cb.Call(cb, err.Error()) + if err != nil { + m.logger.Error(err.Error()) + } + return otto.Value{} + } - return err + return otto.Value{} + + }) } diff --git a/dapp/module/randBytes/module_test.go b/dapp/module/randBytes/module_test.go index c7faa55..fcbc280 100644 --- a/dapp/module/randBytes/module_test.go +++ b/dapp/module/randBytes/module_test.go @@ -5,8 +5,8 @@ import ( "testing" log "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) func TestCreateRandomBytes(t *testing.T) { @@ -15,23 +15,28 @@ func TestCreateRandomBytes(t *testing.T) { mod := New(log.MustGetLogger("")) - vm := duktape.New() + vm := otto.New() require.Nil(t, mod.Register(vm)) - vm.PushGlobalGoFunction("callbackRandomBytes", func(context *duktape.Context) int { - if !context.IsUndefined(0) { + _, err := vm.Call("randomBytes", vm, 3, func(call otto.FunctionCall) otto.Value { + + if !call.Argument(0).IsUndefined() { panic("expected error to be undefined") } - generatedBytes := (context.ToString(-1)) + generatedBytes, err := call.Argument(1).ToString() + if err != nil { + panic(err) + } + if generatedBytes != "1, 4, 6" { - panic("it's not the same bytes") + panic(err) } - return 0 + return otto.Value{} + }) - err := vm.PevalString(`randomBytes(3,callbackRandomBytes)`) require.Nil(t, err) } diff --git a/dapp/module/renderer/dapp/module.go b/dapp/module/renderer/dapp/module.go index be4cea5..e145912 100644 --- a/dapp/module/renderer/dapp/module.go +++ b/dapp/module/renderer/dapp/module.go @@ -6,14 +6,14 @@ import ( validator "github.com/Bit-Nation/panthalassa/dapp/validator" log "github.com/ipfs/go-log" logger "github.com/op/go-logging" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) type Module struct { logger *logger.Logger - vm *duktape.Context - setOpenHandlerChan chan *duktape.Context - getOpenHandlerChan chan chan *duktape.Context + vm *otto.Otto + setOpenHandlerChan chan *otto.Value + getOpenHandlerChan chan chan *otto.Value addCBChan chan *chan error rmCBChan chan *chan error // returns a cb chan from the stack @@ -23,38 +23,38 @@ type Module struct { var sysLog = log.Logger("renderer - dapp") -// setOpenHandler must be called with a callback -// the callback that is passed to `setOpenHandler` -// will be called with an "data" object and a callback -// the callback should be called (with an optional error) -// in order to return from the function -func (m *Module) Register(vm *duktape.Context) error { +func (m *Module) Register(vm *otto.Otto) error { m.vm = vm - _, err := vm.PushGlobalGoFunction("setOpenHandler", func(context *duktape.Context) int { + // setOpenHandler must be called with a callback + // the callback that is passed to `setOpenHandler` + // will be called with an "data" object and a callback + // the callback should be called (with an optional error) + // in order to return from the function + return vm.Set("setOpenHandler", func(call otto.FunctionCall) otto.Value { - sysLog.Debug("set open handler") + //sysLog.Debug("set open handler") // validate function call v := validator.New() v.Set(0, &validator.TypeFunction) - if err := v.Validate(context); err != nil { - m.logger.Error(err.Error()) - return 1 + if err := v.Validate(vm, call); err != nil { + m.logger.Error(err.String()) + return *err } // set renderer - m.setOpenHandlerChan <- context + fn := call.Argument(0) + m.setOpenHandlerChan <- &fn - return 0 + return otto.Value{} }) - return err } // payload can be an arbitrary set of key value pairs (as a json string) func (m *Module) OpenDApp(payload string) error { // fetch handler - handlerChan := make(chan *duktape.Context) + handlerChan := make(chan *otto.Value) m.getOpenHandlerChan <- handlerChan handler := <-handlerChan @@ -64,7 +64,10 @@ func (m *Module) OpenDApp(payload string) error { } // convert context to otto js object - dataObj := "(" + payload + ")" + dataObj, err := m.vm.Object("(" + payload + ")") + if err != nil { + return err + } cbDone := make(chan error) @@ -75,39 +78,31 @@ func (m *Module) OpenDApp(payload string) error { // call the renderer // we pass in data object and a callback - _, err := handler.PushGlobalGoFunction("callbackOpenDApp", func(context *duktape.Context) int { + _, err = handler.Call(*handler, dataObj, func(call otto.FunctionCall) otto.Value { // remove cb chan from state defer func() { m.rmCBChan <- &cbDone }() + // fetch params from the callback call + err := call.Argument(0) + // if there is an error, set it in the response - if !context.IsUndefined(0) && !context.IsNull(0) { - callbackerr := context.ToString(0) - cbDone <- errors.New(callbackerr) - return 1 + if !err.IsUndefined() && !err.IsNull() { + cbDone <- errors.New(err.String()) + return otto.Value{} } cbDone <- nil - return 0 + return otto.Value{} }) if err != nil { m.logger.Error(err.Error()) } - err = handler.PevalString(dataObj) - if err != nil { - m.logger.Error(err.Error()) - } - err = handler.PevalString(`callbackOpenDApp`) - if err != nil { - m.logger.Error(err.Error()) - } - - handler.Call(2) }() @@ -123,8 +118,8 @@ func New(l *logger.Logger) *Module { m := &Module{ logger: l, - setOpenHandlerChan: make(chan *duktape.Context), - getOpenHandlerChan: make(chan chan *duktape.Context), + setOpenHandlerChan: make(chan *otto.Value), + getOpenHandlerChan: make(chan chan *otto.Value), addCBChan: make(chan *chan error), rmCBChan: make(chan *chan error), nextCBChan: make(chan chan *chan error), @@ -133,7 +128,7 @@ func New(l *logger.Logger) *Module { go func() { - openHandler := new(duktape.Context) + openHandler := new(otto.Value) cbChans := map[*chan error]bool{} for { diff --git a/dapp/module/renderer/dapp/module_test.go b/dapp/module/renderer/dapp/module_test.go index f3d90b9..7d12c8b 100644 --- a/dapp/module/renderer/dapp/module_test.go +++ b/dapp/module/renderer/dapp/module_test.go @@ -4,45 +4,37 @@ import ( "testing" log "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) func TestModule_OpenDAppError(t *testing.T) { l := log.MustGetLogger("") - vm := duktape.New() + vm := otto.New() m := New(l) require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackTestModuleOpenDAppError", func(context *duktape.Context) int { + vm.Call("setOpenHandler", vm, func(context otto.Value, cb otto.Value) otto.Value { - if !context.IsObject(0) { - panic("callbackTestFuncCallSuccess : 0 is not an object") + v, err := context.Object().Get("key") + if err != nil { + panic(err) } - if !context.GetPropString(0, "key") { - panic("callbackTestFuncCallSuccess : key missing") - } - - v := context.ToString(-1) - if v != "value" { + if v.String() != "value" { panic("Expected value of key to be: value") } - context.Pop() - context.PushString("I am an error") - context.Call(1) + cb.Call(cb, "I am an error") + + return otto.Value{} - return 0 }) - require.Nil(t, err) - err = vm.PevalString(`setOpenHandler(callbackTestModuleOpenDAppError)`) - require.Nil(t, err) - vm.PevalString(`callbackTestModuleOpenDAppError`) - err = m.OpenDApp(`{key: "value"}`) + + err := m.OpenDApp(`{key: "value"}`) require.EqualError(t, err, "I am an error") } @@ -51,38 +43,29 @@ func TestModule_OpenDAppSuccess(t *testing.T) { l := log.MustGetLogger("") - vm := duktape.New() + vm := otto.New() m := New(l) require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackTestModuleOpenDAppSuccess", func(context *duktape.Context) int { + vm.Call("setOpenHandler", vm, func(context otto.Value, cb otto.Value) otto.Value { - if !context.IsObject(0) { - panic("callbackTestFuncCallSuccess : 0 is not an object") + v, err := context.Object().Get("key") + if err != nil { + panic(err) } - if !context.GetPropString(0, "key") { - panic("callbackTestFuncCallSuccess : key missing") - } - - v := context.ToString(-1) - if v != "value" { + if v.String() != "value" { panic("Expected value of key to be: value") } - context.Pop() - context.PushUndefined() - context.Call(1) + cb.Call(cb, nil) + + return otto.Value{} - return 0 }) - require.Nil(t, err) - err = vm.PevalString(`setOpenHandler(callbackTestModuleOpenDAppSuccess)`) - require.Nil(t, err) - err = vm.PevalString(`callbackTestModuleOpenDAppSuccess`) - require.Nil(t, err) - err = m.OpenDApp(`{key: "value"}`) + + err := m.OpenDApp(`{key: "value"}`) require.Nil(t, err) } @@ -90,19 +73,17 @@ func TestModule_OpenDAppSuccess(t *testing.T) { func TestModule_Close(t *testing.T) { // setup - vm := duktape.New() + vm := otto.New() m := New(nil) require.Nil(t, m.Register(vm)) // set fake open handler - _, err := vm.PushGlobalGoFunction("callbackTestModuleClose", func(context *duktape.Context) int { + _, err := vm.Call("setOpenHandler", vm, func(call otto.FunctionCall) otto.Value { m.Close() - return 0 + return otto.Value{} }) require.Nil(t, err) - err = vm.PevalString(`setOpenHandler(callbackTestModuleClose)`) - require.Nil(t, err) - vm.PevalString(`callbackTestModuleClose`) + require.EqualError(t, m.OpenDApp("{}"), "closed the application") } diff --git a/dapp/module/renderer/message/module.go b/dapp/module/renderer/message/module.go index f96b926..5294d37 100644 --- a/dapp/module/renderer/message/module.go +++ b/dapp/module/renderer/message/module.go @@ -6,14 +6,14 @@ import ( validator "github.com/Bit-Nation/panthalassa/dapp/validator" log "github.com/ipfs/go-log" logger "github.com/op/go-logging" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) type Module struct { logger *logger.Logger - vm *duktape.Context - setRendererChan chan *duktape.Context - getRendererChan chan chan *duktape.Context + vm *otto.Otto + setRendererChan chan *otto.Value + getRendererChan chan chan *otto.Value addCBChan chan *chan resp rmCBChan chan *chan resp closer chan struct{} @@ -30,25 +30,26 @@ var sysLog = log.Logger("renderer - message") // 2. The "callback" should be can be called with two parameters: // 1. an error // 2. the rendered layout -func (m *Module) Register(vm *duktape.Context) error { +func (m *Module) Register(vm *otto.Otto) error { m.vm = vm - _, err := vm.PushGlobalGoFunction("setMessageRenderer", func(context *duktape.Context) int { + return vm.Set("setMessageRenderer", func(call otto.FunctionCall) otto.Value { + sysLog.Debug("set message renderer") // validate function call v := validator.New() v.Set(0, &validator.TypeFunction) - if err := v.Validate(context); err != nil { - m.logger.Error(err.Error()) - return 1 + if err := v.Validate(vm, call); err != nil { + m.logger.Error(err.String()) + return *err } // set renderer - m.setRendererChan <- context + fn := call.Argument(0) + m.setRendererChan <- &fn - return 0 + return otto.Value{} }) - return err } type resp struct { @@ -59,18 +60,22 @@ type resp struct { // payload can be an arbitrary set of key value pairs // should contain the "message" and the "context" tho func (m *Module) RenderMessage(payload string) (string, error) { + // fetch renderer - rendererChan := make(chan *duktape.Context) + rendererChan := make(chan *otto.Value) m.getRendererChan <- rendererChan renderer := <-rendererChan // make sure an renderer has been set - if renderer == nil { + if renderer == nil || !renderer.IsDefined() { return "", errors.New("failed to render message - no open handler set") } // convert context to otto js object - payloadObj := "(" + payload + ")" + payloadObj, err := m.vm.Object("(" + payload + ")") + if err != nil { + return "", err + } cbChan := make(chan resp, 1) m.addCBChan <- &cbChan @@ -79,7 +84,7 @@ func (m *Module) RenderMessage(payload string) (string, error) { // call the message renderer // @todo what happens if we call the callback twice? - _, err := renderer.PushGlobalGoFunction("callbackRenderMessage", func(context *duktape.Context) int { + _, err = renderer.Call(*renderer, payloadObj, func(call otto.FunctionCall) otto.Value { // delete cb chan from stack when we are done defer func() { @@ -87,38 +92,31 @@ func (m *Module) RenderMessage(payload string) (string, error) { }() // fetch params from the callback call + err := call.Argument(0) + layout := call.Argument(1) + r := resp{} // if there is an error, set it in the response - if !context.IsUndefined(0) && !context.IsNull(0) { - callbackerr := context.ToString(0) - r.error = errors.New(callbackerr) + if !err.IsUndefined() && !err.IsNull() { + r.error = errors.New(err.String()) } // set the layout in the response - if context.IsString(1) { - layout := context.ToString(1) - r.layout = layout + if layout.IsString() { + r.layout = layout.String() } cbChan <- r - return 0 + return otto.Value{} }) - if err != nil { - m.logger.Error(err.Error()) - } - err = renderer.PevalString(payloadObj) - if err != nil { - m.logger.Error(err.Error()) - } - err = renderer.PevalString(`callbackRenderMessage`) + if err != nil { m.logger.Error(err.Error()) } - renderer.Call(2) }() r := <-cbChan @@ -133,8 +131,8 @@ func (m *Module) Close() error { func New(l *logger.Logger) *Module { m := &Module{ logger: l, - setRendererChan: make(chan *duktape.Context), - getRendererChan: make(chan chan *duktape.Context), + setRendererChan: make(chan *otto.Value), + getRendererChan: make(chan chan *otto.Value), addCBChan: make(chan *chan resp), rmCBChan: make(chan *chan resp), closer: make(chan struct{}), @@ -142,7 +140,7 @@ func New(l *logger.Logger) *Module { go func() { - renderer := new(duktape.Context) + renderer := new(otto.Value) cbChans := map[*chan resp]bool{} for { diff --git a/dapp/module/renderer/message/module_test.go b/dapp/module/renderer/message/module_test.go index 4bc5768..aefd903 100644 --- a/dapp/module/renderer/message/module_test.go +++ b/dapp/module/renderer/message/module_test.go @@ -4,29 +4,28 @@ import ( "testing" log "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) func TestModule_RenderMessageError(t *testing.T) { l := log.MustGetLogger("") - vm := duktape.New() + vm := otto.New() m := New(l) require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackTestModuleRenderMessageError", func(context *duktape.Context) int { - context.PushString("I am an error") - context.Call(1) - return 0 + + vm.Call("setMessageRenderer", vm, func(payload otto.Value, cb otto.Value) otto.Value { + + cb.Call(cb, "I am an error") + + return otto.Value{} + }) - require.Nil(t, err) - err = vm.PevalString("setMessageRenderer(callbackTestModuleRenderMessageError)") - require.Nil(t, err) - vm.PevalString(`callbackTestModuleRenderMessageError`) - _, err = m.RenderMessage(`{}`) + _, err := m.RenderMessage(`{}`) require.EqualError(t, err, "I am an error") } @@ -35,35 +34,28 @@ func TestModule_RenderMessageSuccess(t *testing.T) { l := log.MustGetLogger("") - vm := duktape.New() + vm := otto.New() m := New(l) require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackTestModuleRenderMessageSuccess", func(context *duktape.Context) int { - if !context.IsObject(0) { - panic("callbackTestFuncCallSuccess : 0 is not an object") - } - if !context.GetPropString(0, "message") { - panic("callbackTestFuncCallSuccess : message missing") + vm.Call("setMessageRenderer", vm, func(payload otto.Value, cb otto.Value) otto.Value { + + msg, err := payload.Object().Get("message") + if err != nil { + panic(err) } - if !context.IsObject(-1) { + if !msg.IsObject() { panic("Expected message to be an object") } - context.Pop() - context.PushUndefined() - context.PushString(`{}`) - context.Call(2) + cb.Call(cb, nil, "{}") - return 0 + return otto.Value{} }) - require.Nil(t, err) - err = vm.PevalString("setMessageRenderer(callbackTestModuleRenderMessageSuccess)") - require.Nil(t, err) - vm.PevalString(`callbackTestModuleRenderMessageSuccess`) + layout, err := m.RenderMessage(`{message: {}, context: {}}`) require.Nil(t, err) require.Equal(t, "{}", layout) @@ -72,19 +64,16 @@ func TestModule_RenderMessageSuccess(t *testing.T) { func TestModule_Close(t *testing.T) { - vm := duktape.New() + vm := otto.New() m := New(log.MustGetLogger("")) require.Nil(t, m.Register(vm)) - _, err := vm.PushGlobalGoFunction("callbackTestModuleClose", func(context *duktape.Context) int { + vm.Call("setMessageRenderer", vm, func(call otto.FunctionCall) otto.Value { m.Close() - return 0 + return otto.Value{} }) - require.Nil(t, err) - err = vm.PevalString(`setMessageRenderer(callbackTestModuleClose)`) - require.Nil(t, err) - vm.PevalString(`callbackTestModuleClose`) - _, err = m.RenderMessage("{}") + + _, err := m.RenderMessage("{}") require.EqualError(t, err, "closed the application") } diff --git a/dapp/module/sendEthTx/module.go b/dapp/module/sendEthTx/module.go index 95cb500..0abb46b 100644 --- a/dapp/module/sendEthTx/module.go +++ b/dapp/module/sendEthTx/module.go @@ -8,7 +8,7 @@ import ( validator "github.com/Bit-Nation/panthalassa/dapp/validator" log "github.com/ipfs/go-log" logger "github.com/op/go-logging" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) var sysLogger = log.Logger("send eth tx") @@ -37,104 +37,84 @@ func (m *Module) Close() error { return nil } -func (m *Module) Register(vm *duktape.Context) error { +func (m *Module) Register(vm *otto.Otto) error { // send an ethereum transaction // musst be called with an object that holds value, to and data - _, err := vm.PushGlobalGoFunction("sendETHTransaction", func(context *duktape.Context) int { - var itemsToPopBeforeCallback int + return vm.Set("sendETHTransaction", func(call otto.FunctionCall) otto.Value { + sysLogger.Debug("send eth transaction") // validate function call v := validator.New() v.Set(0, &validator.TypeObject) v.Set(1, &validator.TypeFunction) - // utils to handle an occurred error - handleError := func(errMsg string) int { - if context.IsFunction(1) { - context.PopN(itemsToPopBeforeCallback) - context.PushString(errMsg) - context.Call(1) - return 0 - } - m.logger.Error(errMsg) - return 1 + if err := v.Validate(vm, call); err != nil { + m.logger.Error(err.String()) + return *err } - if err := v.Validate(context); err != nil { - m.logger.Error(err.Error()) - return 1 - } + cb := call.Argument(1) // validate transaction object + obj := call.Argument(0).Object() objVali := validator.NewObjValidator() objVali.Set("value", validator.ObjTypeString, true) objVali.Set("to", validator.ObjTypeAddress, true) objVali.Set("data", validator.ObjTypeString, true) - if err := objVali.Validate(vm, 0); err != nil { - handleError(err.Error()) - return 1 + if err := objVali.Validate(vm, *obj); err != nil { + cb.Call(cb, err.String()) + return otto.Value{} } + // execute in the context of the throttling // request limitation - throttlingFunc := func(vmDone chan struct{}) { - defer func() { - <-vmDone - }() - if !context.GetPropString(0, "to") { - err := errors.New(`key "to" doesn't exist`) - handleError(err.Error()) + m.throttling.Exec(func() { + + to, err := obj.Get("to") + if err != nil { + if _, err := cb.Call(cb, err.Error()); err != nil { + m.logger.Error(err.Error()) + } return } - to := context.ToString(-1) - itemsToPopBeforeCallback++ - itemsToPopBeforeCallback++ - if !context.GetPropString(0, "value") { - err := errors.New(`key "value" doesn't exist`) - handleError(err.Error()) + value, err := obj.Get("value") + if err != nil { + if _, err := cb.Call(cb, err.Error()); err != nil { + m.logger.Error(err.Error()) + } return } - value := context.ToString(-1) - itemsToPopBeforeCallback++ - itemsToPopBeforeCallback++ - if !context.GetPropString(0, "data") { - err := errors.New(`key "data" doesn't exist`) - handleError(err.Error()) + data, err := obj.Get("data") + if err != nil { + if _, err := cb.Call(cb, err.Error()); err != nil { + m.logger.Error(err.Error()) + } return } - data := context.ToString(-1) - itemsToPopBeforeCallback++ - itemsToPopBeforeCallback++ // try to sign a transaction tx, err := m.ethApi.SendEthereumTransaction( - value, - to, - data, + value.String(), + to.String(), + data.String(), ) // exit on error if err != nil { - handleError(err.Error()) + cb.Call(cb, err.Error()) + return } // call callback with transaction - // See https://duktape.org/api.html - // Each function description includes Stack : (No effect on value stack) or a description of the effect it has on the stack - // When we call functions which modify the stack, we need to Pop them in order for things to work as intended - context.PopN(itemsToPopBeforeCallback) - context.PushUndefined() - context.PushString(tx) - context.Call(2) - return + cb.Call(cb, nil, tx) - } - m.throttling.Exec(throttlingFunc) + }) - return 0 + return otto.Value{} }) - return err + } diff --git a/dapp/module/sendEthTx/module_test.go b/dapp/module/sendEthTx/module_test.go index 3310243..78bca9d 100644 --- a/dapp/module/sendEthTx/module_test.go +++ b/dapp/module/sendEthTx/module_test.go @@ -5,8 +5,8 @@ import ( "time" log "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) type testApi struct { @@ -21,7 +21,7 @@ func TestSuccessCall(t *testing.T) { logger := log.MustGetLogger("") - vm := duktape.New() + vm := otto.New() m := New(&testApi{ send: func(value, to, data string) (string, error) { @@ -40,33 +40,35 @@ func TestSuccessCall(t *testing.T) { require.Nil(t, m.Register(vm)) - txReq := `({ - "value": "10000", + txReq, err := vm.Object(`({ + "value": "10000" "to": "0xee60a19d0850b51b8598ca2ceb9acae3f452943d", "data": "0xf3..." - })` + })`) + require.Nil(t, err) wait := make(chan bool) - _, err := vm.PushGlobalGoFunction("callbackSendETHTransaction", func(context *duktape.Context) int { - - if !context.IsUndefined(0) { - panic("expected error to be undefined") - } + _, err = vm.Call( + "sendETHTransaction", + vm, + txReq, + func(error, transaction string) otto.Value { - transaction := (context.ToString(-1)) - if transaction != "{}" { - // it's ok to assert {} - // this is just a mock - panic("expected transaction to be {}") - } + if error != "undefined" { + panic("expected error to be undefined") + } - wait <- true - return 0 - }) - require.Nil(t, err) + if transaction != "{}" { + // it's ok to assert {} + // this is just a mock + panic("expected transaction to be {}") + } - go vm.PevalString(`sendETHTransaction(` + txReq + `,callbackSendETHTransaction)`) + wait <- true + return otto.Value{} + }, + ) require.Nil(t, err) select { diff --git a/dapp/module/uuidv4/module.go b/dapp/module/uuidv4/module.go index 0df492f..3a07ba1 100644 --- a/dapp/module/uuidv4/module.go +++ b/dapp/module/uuidv4/module.go @@ -1,12 +1,11 @@ package uuidv4 import ( - log "github.com/ipfs/go-log" - validator "github.com/Bit-Nation/panthalassa/dapp/validator" + log "github.com/ipfs/go-log" logger "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" uuid "github.com/satori/go.uuid" - duktape "gopkg.in/olebedev/go-duktape.v3" ) var newUuid = uuid.NewV4 @@ -29,37 +28,42 @@ func (r *UUIDV4) Close() error { return nil } -func (r *UUIDV4) Register(vm *duktape.Context) error { +func (r *UUIDV4) Register(vm *otto.Otto) error { - _, err := vm.PushGlobalGoFunction("uuidV4", func(context *duktape.Context) int { + return vm.Set("uuidV4", func(call otto.FunctionCall) otto.Value { sysLogger.Debug("generate uuidv4") // validate function call v := validator.New() v.Set(0, &validator.TypeFunction) - if err := v.Validate(context); err != nil { - //vm.Run(`throw new Error("uuidV4 expects an callback as it's parameter")`) - return 1 + if err := v.Validate(vm, call); err != nil { + vm.Run(`throw new Error("uuidV4 expects an callback as it's parameter")`) + return otto.Value{} } + cb := call.Argument(0) + // create uuid id, err := newUuid() + // call callback with error if err != nil { - context.PushString(err.Error()) - context.PushUndefined() - context.Call(2) - return 1 + _, err = cb.Call(call.This, err.Error()) + if err != nil { + r.logger.Error(err.Error()) + } + return otto.Value{} } // call callback with uuid - context.PushUndefined() - context.PushString(id.String()) - context.Call(2) + _, err = cb.Call(call.This, nil, id.String()) + if err != nil { + r.logger.Error(err.Error()) + } - return 0 + return otto.Value{} }) - return err + } diff --git a/dapp/module/uuidv4/module_test.go b/dapp/module/uuidv4/module_test.go index 03ab298..228b14c 100644 --- a/dapp/module/uuidv4/module_test.go +++ b/dapp/module/uuidv4/module_test.go @@ -6,9 +6,9 @@ import ( "time" log "github.com/op/go-logging" + otto "github.com/robertkrimen/otto" uuid "github.com/satori/go.uuid" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) func TestUUIDV4ModelSuccess(t *testing.T) { @@ -20,19 +20,16 @@ func TestUUIDV4ModelSuccess(t *testing.T) { return uuid.FromString("9b781c39-2bd3-41c6-a246-150a9f4421a3") } - vm := duktape.New() - - require.Nil(t, m.Register(vm)) - - _, err := vm.PushGlobalGoFunction("test", func(context *duktape.Context) int { - require.True(t, context.IsUndefined(0)) - require.Equal(t, "9b781c39-2bd3-41c6-a246-150a9f4421a3", context.ToString(1)) - return 0 + vm := otto.New() + vm.Set("test", func(call otto.FunctionCall) otto.Value { + require.True(t, call.Argument(0).IsUndefined()) + require.Equal(t, "9b781c39-2bd3-41c6-a246-150a9f4421a3", call.Argument(1).String()) + return otto.Value{} }) - require.Nil(t, err) + require.Nil(t, m.Register(vm)) - vm.PevalString(`uuidV4(test)`) + vm.Run(`uuidV4(test)`) } @@ -45,28 +42,28 @@ func TestUUIDV4ModelError(t *testing.T) { return uuid.UUID{}, errors.New("I am a nice error message") } - vm := duktape.New() + vm := otto.New() require.Nil(t, m.Register(vm)) wait := make(chan bool, 1) - _, err := vm.PushGlobalGoFunction("callbackUuidV4", func(context *duktape.Context) int { - if context.ToString(0) != "I am a nice error message" { + vm.Call("uuidV4", vm, func(call otto.FunctionCall) otto.Value { + + if call.Argument(0).String() != "I am a nice error message" { panic("expected error message: I am a nice error message") } - if !context.IsUndefined(1) { + if !call.Argument(1).IsUndefined() { panic("id should be undefined") } wait <- true - return 0 + return otto.Value{} + }) - require.Nil(t, err) - vm.PevalString("uuidV4(callbackUuidV4)") select { case <-wait: case <-time.After(time.Second): diff --git a/dapp/request_limitation/count_throttling.go b/dapp/request_limitation/count_throttling.go index 9723590..1e03bff 100644 --- a/dapp/request_limitation/count_throttling.go +++ b/dapp/request_limitation/count_throttling.go @@ -11,13 +11,12 @@ type CountThrottling struct { concurrency uint coolDown time.Duration // the channel should be called when the function succeed - stack chan func(chan struct{}, chan struct{}) + stack chan func(chan struct{}) maxQueue uint queueFullError error currentChan chan chan uint inWorkChan chan chan uint decCurrent chan struct{} - vmDone chan struct{} } var countThrottlingSleep = time.Second @@ -28,13 +27,12 @@ func NewCountThrottling(concurrency uint, coolDown time.Duration, maxQueue uint, t := &CountThrottling{ concurrency: concurrency, coolDown: coolDown, - stack: make(chan func(chan struct{}, chan struct{}), maxQueue), + stack: make(chan func(chan struct{}), maxQueue), maxQueue: maxQueue, queueFullError: queueFullError, currentChan: make(chan chan uint), inWorkChan: make(chan chan uint), decCurrent: make(chan struct{}), - vmDone: make(chan struct{}), } // "in work" related channels @@ -100,7 +98,7 @@ func NewCountThrottling(concurrency uint, coolDown time.Duration, maxQueue uint, case job := <-t.stack: incInWork <- struct{}{} incCurrent <- struct{}{} - go job(t.decCurrent, t.vmDone) + go job(t.decCurrent) go func() { <-time.After(t.coolDown) decInWork <- struct{}{} @@ -133,11 +131,10 @@ func (t *CountThrottling) Current() uint { return <-cq } -func (t *CountThrottling) Exec(cb func(dec chan struct{}, vmDone chan struct{})) error { +func (t *CountThrottling) Exec(cb func(dec chan struct{})) error { if len(t.stack) >= int(t.maxQueue) { return t.queueFullError } t.stack <- cb - t.vmDone <- struct{}{} return nil } diff --git a/dapp/request_limitation/count_throttling_test.go b/dapp/request_limitation/count_throttling_test.go index 5d3c865..3692486 100644 --- a/dapp/request_limitation/count_throttling_test.go +++ b/dapp/request_limitation/count_throttling_test.go @@ -9,6 +9,7 @@ import ( ) func TestCountThrottling(t *testing.T) { + ct := NewCountThrottling( 3, time.Second*1, @@ -22,30 +23,37 @@ func TestCountThrottling(t *testing.T) { // decrease channel var decChan chan struct{} - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - <-vmDone + require.Nil(t, ct.Exec(func(dec chan struct{}) { decChan = dec })) - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - <-vmDone + require.Nil(t, ct.Exec(func(dec chan struct{}) { + + })) + require.Nil(t, ct.Exec(func(dec chan struct{}) { + + })) + require.Nil(t, ct.Exec(func(dec chan struct{}) { + + })) + require.Nil(t, ct.Exec(func(dec chan struct{}) { + + })) + require.Nil(t, ct.Exec(func(dec chan struct{}) { + + })) + require.Nil(t, ct.Exec(func(dec chan struct{}) { + + })) + require.Nil(t, ct.Exec(func(dec chan struct{}) { + + })) + require.Nil(t, ct.Exec(func(dec chan struct{}) { + })) - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - <-vmDone + require.Nil(t, ct.Exec(func(dec chan struct{}) { + })) - //require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - //})) - //require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - //})) - //require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - //})) - //require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - //})) - //require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - //})) - //require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - //})) - //require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - //})) + // wait for queue to pick up the jobs time.Sleep(time.Millisecond * 10) require.Equal(t, uint(3), ct.inWork()) @@ -64,9 +72,7 @@ func TestCountThrottling(t *testing.T) { // decrease the amount of current // to make sure worker will pick up new job decChan <- struct{}{} - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - <-vmDone - })) + // wait for queue to pick up new jobs time.Sleep(time.Millisecond * 10) require.Equal(t, uint(1), ct.inWork()) @@ -76,33 +82,28 @@ func TestCountThrottling(t *testing.T) { func TestCountThrottlingFullError(t *testing.T) { ct := NewCountThrottling( - 1, + 0, time.Second*1, 5, errors.New("queue full error"), ) - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - <-vmDone + require.Nil(t, ct.Exec(func(dec chan struct{}) { dec <- struct{}{} })) - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - <-vmDone + require.Nil(t, ct.Exec(func(dec chan struct{}) { dec <- struct{}{} })) - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - <-vmDone + require.Nil(t, ct.Exec(func(dec chan struct{}) { dec <- struct{}{} })) - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - <-vmDone + require.Nil(t, ct.Exec(func(dec chan struct{}) { dec <- struct{}{} })) - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { - <-vmDone + require.Nil(t, ct.Exec(func(dec chan struct{}) { dec <- struct{}{} })) - require.Nil(t, ct.Exec(func(dec chan struct{}, vmDone chan struct{}) { <-vmDone })) + require.EqualError(t, ct.Exec(func(dec chan struct{}) {}), "queue full error") } diff --git a/dapp/request_limitation/throttling.go b/dapp/request_limitation/throttling.go index 35f93fe..acc333f 100644 --- a/dapp/request_limitation/throttling.go +++ b/dapp/request_limitation/throttling.go @@ -7,10 +7,9 @@ import ( type Throttling struct { concurrency uint coolDown time.Duration - stack chan func(chan struct{}) + stack chan func() maxQueue uint queueFullError error - vmDone chan struct{} } func (t *Throttling) Close() error { @@ -24,10 +23,9 @@ func NewThrottling(concurrency uint, coolDown time.Duration, maxQueue uint, queu t := &Throttling{ concurrency: concurrency, coolDown: coolDown, - stack: make(chan func(chan struct{}), maxQueue), + stack: make(chan func(), maxQueue), maxQueue: maxQueue, queueFullError: queueFullError, - vmDone: make(chan struct{}), } inWorkChan := make(chan chan uint) @@ -81,7 +79,7 @@ func NewThrottling(concurrency uint, coolDown time.Duration, maxQueue uint, queu select { case job := <-t.stack: incInWork <- struct{}{} - go job(t.vmDone) + go job() go func() { <-time.After(t.coolDown) decInWork <- struct{}{} @@ -93,11 +91,10 @@ func NewThrottling(concurrency uint, coolDown time.Duration, maxQueue uint, queu return t } -func (t *Throttling) Exec(cb func(vmDone chan struct{})) error { +func (t *Throttling) Exec(cb func()) error { if len(t.stack) >= int(t.maxQueue) { return t.queueFullError } t.stack <- cb - t.vmDone <- struct{}{} return nil } diff --git a/dapp/request_limitation/throttling_test.go b/dapp/request_limitation/throttling_test.go index 4c5ed80..c6bc64b 100644 --- a/dapp/request_limitation/throttling_test.go +++ b/dapp/request_limitation/throttling_test.go @@ -10,10 +10,10 @@ import ( func TestThrottling_Exec(t *testing.T) { - throttling := NewThrottling(1, time.Second, 1, errors.New("queue is full")) + throttling := NewThrottling(0, time.Second, 1, errors.New("queue is full")) - require.Nil(t, throttling.Exec(func(vmDone chan struct{}) { <-vmDone })) - require.Nil(t, throttling.Exec(func(vmDone chan struct{}) { <-vmDone })) + require.Nil(t, throttling.Exec(func() {})) + require.EqualError(t, throttling.Exec(func() {}), "queue is full") } diff --git a/dapp/validator/call.go b/dapp/validator/call.go index fc24420..498b487 100644 --- a/dapp/validator/call.go +++ b/dapp/validator/call.go @@ -6,34 +6,34 @@ import ( "sort" "sync" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) -type Validator = func(context *duktape.Context, position int) error +type Validator = func(call otto.FunctionCall, position int) error -var TypeFunction = func(context *duktape.Context, position int) error { - if !context.IsFunction(position) { +var TypeFunction = func(call otto.FunctionCall, position int) error { + if !call.Argument(position).IsFunction() { return errors.New(fmt.Sprintf("expected parameter %d to be of type function", position)) } return nil } -var TypeNumber = func(context *duktape.Context, position int) error { - if !context.IsNumber(position) { +var TypeNumber = func(call otto.FunctionCall, position int) error { + if !call.Argument(position).IsNumber() { return errors.New(fmt.Sprintf("expected parameter %d to be of type number", position)) } return nil } -var TypeString = func(context *duktape.Context, position int) error { - if !context.IsString(position) { +var TypeString = func(call otto.FunctionCall, position int) error { + if !call.Argument(position).IsString() { return errors.New(fmt.Sprintf("expected parameter %d to be of type string", position)) } return nil } -var TypeObject = func(context *duktape.Context, position int) error { - if !context.IsObject(position) { +var TypeObject = func(call otto.FunctionCall, position int) error { + if !call.Argument(position).IsObject() { return errors.New(fmt.Sprintf("expected parameter %d to be of type object", position)) } return nil @@ -51,7 +51,7 @@ func (v *CallValidator) Set(index int, validator *Validator) { v.rules[index] = validator } -func (v *CallValidator) Validate(vm *duktape.Context) error { +func (v *CallValidator) Validate(vm *otto.Otto, call otto.FunctionCall) *otto.Value { v.lock.Lock() defer v.lock.Unlock() @@ -66,14 +66,14 @@ func (v *CallValidator) Validate(vm *duktape.Context) error { validator, exist := v.rules[k] if !exist { - ve := fmt.Errorf("ValidationError: couldn't find validator for type: %d", k) - return ve + ve := vm.MakeCustomError("ValidationError", fmt.Sprintf("couldn't find validator for type: %d", k)) + return &ve } v := *validator - if err := v(vm, k); err != nil { - ve := fmt.Errorf("ValidationError: %s", err.Error()) - return ve + if err := v(call, k); err != nil { + ve := vm.MakeCustomError("ValidationError", err.Error()) + return &ve } } diff --git a/dapp/validator/object.go b/dapp/validator/object.go index 5b21c1e..5969266 100644 --- a/dapp/validator/object.go +++ b/dapp/validator/object.go @@ -6,42 +6,42 @@ import ( "sync" eth "github.com/ethereum/go-ethereum/common" - duktape "gopkg.in/olebedev/go-duktape.v3" + otto "github.com/robertkrimen/otto" ) -type ObjValueValidator func(context *duktape.Context, position int) error +type ObjValueValidator func(value otto.Value, objKey string) error // validate an address -var ObjTypeAddress = func(context *duktape.Context, position int) error { - err := errors.New(fmt.Sprintf("Expected %s to be an ethereum address", context.ToString(position))) - if !context.IsString(position) { +var ObjTypeAddress = func(value otto.Value, objKey string) error { + err := errors.New(fmt.Sprintf("Expected %s to be an ethereum address", objKey)) + if !value.IsString() { return err } - if !eth.IsHexAddress(context.ToString(position)) { + if !eth.IsHexAddress(value.String()) { return err } return nil } // Validate if value is a string -var ObjTypeString = func(context *duktape.Context, position int) error { - if !context.IsString(position) { - return errors.New(fmt.Sprintf("Expected %s to be a string", context.ToString(position))) +var ObjTypeString = func(value otto.Value, objKey string) error { + if !value.IsString() { + return errors.New(fmt.Sprintf("Expected %s to be a string", objKey)) } return nil } // validate if value is an object -var ObjTypeObject = func(context *duktape.Context, position int) error { - if !context.IsObject(position) { - return fmt.Errorf("expected %s to be a object", context.ToString(position)) +var ObjTypeObject = func(value otto.Value, objKey string) error { + if !value.IsObject() { + return fmt.Errorf("expected %s to be a object", objKey) } return nil } -var ObjTypeBool = func(context *duktape.Context, position int) error { - if !context.IsBoolean(position) { - return fmt.Errorf("expected %s to be a bool", context.ToString(position)) +var ObjTypeBool = func(value otto.Value, objKey string) error { + if !value.IsBoolean() { + return fmt.Errorf("expected %s to be a bool", objKey) } return nil } @@ -76,20 +76,27 @@ func (v *ObjValidator) Set(key string, validator ObjValueValidator, required boo } -func (v *ObjValidator) Validate(context *duktape.Context, position int) error { +func (v *ObjValidator) Validate(vm *otto.Otto, obj otto.Object) *otto.Value { v.lock.Lock() defer v.lock.Unlock() for objKey, rule := range v.rules { + keyExist := false - if context.HasPropString(position, objKey) { - keyExist = true + for _, k := range obj.Keys() { + if k == objKey { + keyExist = true + } } + // exit when key is required but missing if !keyExist && rule.required { - e := fmt.Errorf("ValidationError: Missing value for required key: %s", objKey) - return e + e := vm.MakeCustomError( + "ValidationError", + fmt.Sprintf("Missing value for required key: %s", objKey), + ) + return &e } // in the case the ke doesn't exist we should just move on @@ -98,15 +105,22 @@ func (v *ObjValidator) Validate(context *duktape.Context, position int) error { } // get value for key - if !context.GetPropString(position, objKey) { - e := fmt.Errorf("InternalError: Key doesn't exist %s", objKey) - return e + value, err := obj.Get(objKey) + if err != nil { + e := vm.MakeCustomError( + "InternalError", + err.Error(), + ) + return &e } + // validate value - // @TODO find out why -1 works here and "position" doesnt - if err := rule.valueType(context, -1); err != nil { - //e := fmt.Errorf("ValidationError : Missing value for required key: %s", context.ToString(position)) - return err + if err := rule.valueType(value, objKey); err != nil { + e := vm.MakeCustomError( + "ValidationError", + err.Error(), + ) + return &e } } diff --git a/dapp/validator/object_test.go b/dapp/validator/object_test.go index 0b7c856..826fd68 100644 --- a/dapp/validator/object_test.go +++ b/dapp/validator/object_test.go @@ -3,8 +3,8 @@ package validator import ( "testing" + otto "github.com/robertkrimen/otto" require "github.com/stretchr/testify/require" - duktape "gopkg.in/olebedev/go-duktape.v3" ) func TestNewObjValidatorOptionalFields(t *testing.T) { @@ -12,12 +12,12 @@ func TestNewObjValidatorOptionalFields(t *testing.T) { v := NewObjValidator() v.Set("to", ObjTypeAddress, false) - vm := duktape.New() - err := vm.PevalString(`({})`) + vm := otto.New() + ob, err := vm.Object(`({})`) require.Nil(t, err) // expect no error since it's ok omit the address - validationErr := v.Validate(vm, -1) + validationErr := v.Validate(vm, *ob) require.Nil(t, validationErr) } @@ -30,11 +30,12 @@ func TestNewObjValidationRequiredFields(t *testing.T) { v := NewObjValidator() v.Set("to", ObjTypeAddress, true) - vm := duktape.New() - err := vm.PevalString(`({"to": "0x0b078896a3d9166da5c37ae52a5809aca48630d4"})`) + vm := otto.New() + ob, err := vm.Object(`({"to": "0x0b078896a3d9166da5c37ae52a5809aca48630d4"})`) require.Nil(t, err) + // expect no error since we provide the address - require.Nil(t, v.Validate(vm, -1)) + require.Nil(t, v.Validate(vm, *ob)) /** * Test required field - with error @@ -42,10 +43,11 @@ func TestNewObjValidationRequiredFields(t *testing.T) { v = NewObjValidator() v.Set("to", ObjTypeAddress, false) - vm = duktape.New() - err = vm.PevalString(`({})`) + vm = otto.New() + ob, err = vm.Object(`({})`) require.Nil(t, err) + // expect error since we don't pass the required address in - require.Nil(t, v.Validate(vm, -1)) + require.Nil(t, v.Validate(vm, *ob)) } diff --git a/db/bolt_to_storm.go b/db/bolt_to_storm.go index 31c695b..e083294 100644 --- a/db/bolt_to_storm.go +++ b/db/bolt_to_storm.go @@ -11,8 +11,8 @@ import ( queue "github.com/Bit-Nation/panthalassa/queue" x3dh "github.com/Bit-Nation/x3dh" storm "github.com/asdine/storm" - bolt "github.com/coreos/bbolt" dr "github.com/tiabc/doubleratchet" + bolt "go.etcd.io/bbolt" ) type BoltToStormMigration struct { diff --git a/db/migration.go b/db/migration.go index 935a4f9..364f367 100644 --- a/db/migration.go +++ b/db/migration.go @@ -13,7 +13,7 @@ import ( "time" storm "github.com/asdine/storm" - bolt "github.com/coreos/bbolt" + bolt "go.etcd.io/bbolt" ) type Migration interface { diff --git a/db/migration_test.go b/db/migration_test.go index 47685b0..f6d9228 100644 --- a/db/migration_test.go +++ b/db/migration_test.go @@ -11,8 +11,8 @@ import ( "time" storm "github.com/asdine/storm" - bolt "github.com/coreos/bbolt" require "github.com/stretchr/testify/require" + bolt "go.etcd.io/bbolt" ) type migration struct { diff --git a/db/test_utils.go b/db/test_utils.go index d1ba7f6..d2ae9a3 100644 --- a/db/test_utils.go +++ b/db/test_utils.go @@ -1,13 +1,14 @@ package db import ( - km "github.com/Bit-Nation/panthalassa/keyManager" - ks "github.com/Bit-Nation/panthalassa/keyStore" - mnemonic "github.com/Bit-Nation/panthalassa/mnemonic" - bolt "github.com/coreos/bbolt" "os" "path/filepath" "time" + + km "github.com/Bit-Nation/panthalassa/keyManager" + ks "github.com/Bit-Nation/panthalassa/keyStore" + mnemonic "github.com/Bit-Nation/panthalassa/mnemonic" + bolt "go.etcd.io/bbolt" ) func createKeyManager() *km.KeyManager { diff --git a/mobile_interface.go b/mobile_interface.go index 2a57279..b7702b2 100644 --- a/mobile_interface.go +++ b/mobile_interface.go @@ -23,10 +23,10 @@ import ( queue "github.com/Bit-Nation/panthalassa/queue" uiapi "github.com/Bit-Nation/panthalassa/uiapi" "github.com/asdine/storm" - bolt "github.com/coreos/bbolt" proto "github.com/golang/protobuf/proto" log "github.com/ipfs/go-log" ma "github.com/multiformats/go-multiaddr" + bolt "go.etcd.io/bbolt" ) var panthalassaInstance *Panthalassa diff --git a/queue/test_utils.go b/queue/test_utils.go index 572a3d1..70f8e1e 100644 --- a/queue/test_utils.go +++ b/queue/test_utils.go @@ -7,7 +7,8 @@ import ( "crypto/rand" "encoding/hex" - bolt "github.com/coreos/bbolt" + + bolt "go.etcd.io/bbolt" ) type testProcessor struct { From f5b977c0a2b2623f7a811fca3e1aa995c30f11e5 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Thu, 27 Sep 2018 11:05:12 -0700 Subject: [PATCH 30/38] [docs] decrypt content --- documents/call.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/documents/call.go b/documents/call.go index 827b6c0..ea058d2 100644 --- a/documents/call.go +++ b/documents/call.go @@ -229,7 +229,16 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int if err := d.s.db.One("ID", int(docID), &doc); err != nil { return map[string]interface{}{}, err } - + + // decrypt document content + docContent, err := d.km.AESDecrypt(doc.EncryptedContent) + if err != nil { + return map[string]interface{}{}, err + } + + // assign plain document content + doc.Content = docContent + // hash document docHash, err := mh.Sum(doc.Content, mh.SHA2_256, -1) if err != nil { From ceebf38a8caa4c06a135298244f72d20a069066f Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Thu, 27 Sep 2018 11:06:30 -0700 Subject: [PATCH 31/38] [docs] added content decryption --- documents/call.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/documents/call.go b/documents/call.go index a4d4c47..2d13f31 100644 --- a/documents/call.go +++ b/documents/call.go @@ -232,7 +232,16 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int if err != nil { return map[string]interface{}{}, err } - + + // decrypt document content + docContent, err := d.km.AESDecrypt(doc.EncryptedContent) + if err != nil { + return map[string]interface{}{}, err + } + + // assign plain document content + doc.Content = docContent + docContentCID := cid.NewCidV1(cid.Raw, docHash).Bytes() // attach cid to document From d8c893a0d48c811240c9d822d35464b997d2fdc1 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Thu, 27 Sep 2018 19:16:10 -0700 Subject: [PATCH 32/38] [docs] added new notary contract --- documents/call.go | 13 +- documents/notary_contract.go | 930 ++++++++++++++++++++++++++++++++++- 2 files changed, 934 insertions(+), 9 deletions(-) diff --git a/documents/call.go b/documents/call.go index 2d13f31..29f7855 100644 --- a/documents/call.go +++ b/documents/call.go @@ -232,16 +232,16 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int if err != nil { return map[string]interface{}{}, err } - + // decrypt document content docContent, err := d.km.AESDecrypt(doc.EncryptedContent) if err != nil { return map[string]interface{}{}, err } - + // assign plain document content doc.Content = docContent - + docContentCID := cid.NewCidV1(cid.Raw, docHash).Bytes() // attach cid to document @@ -261,10 +261,17 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int return map[string]interface{}{}, err } + // fetch the notary fee + notaryFee, err := d.n.NotaryFee(nil) + if err != nil { + return nil, err + } + // submit tx to chain tx, err := d.n.NotarizeTwo(&bind.TransactOpts{ From: common.HexToAddress(ethAddr), Signer: d.km.SignEthTx, + Value: notaryFee, }, docContentCID, cidSignature) if err != nil { return map[string]interface{}{}, err diff --git a/documents/notary_contract.go b/documents/notary_contract.go index 9a89e80..6b191e1 100644 --- a/documents/notary_contract.go +++ b/documents/notary_contract.go @@ -7,25 +7,27 @@ import ( "math/big" "strings" + ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" ) // NotaryABI is the input ABI used to generate the binding from. -const NotaryABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"records\",\"outputs\":[{\"name\":\"notarisedData\",\"type\":\"bytes\"},{\"name\":\"timestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_notarisedData\",\"type\":\"bytes\"}],\"name\":\"record\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"},{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_record\",\"type\":\"bytes\"}],\"name\":\"notarize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" +const NotaryABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"records\",\"outputs\":[{\"name\":\"notarisedData\",\"type\":\"bytes\"},{\"name\":\"timestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"setNotarisationFee\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"notarisationFee\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_notarisedData\",\"type\":\"bytes\"}],\"name\":\"record\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"},{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_record\",\"type\":\"bytes\"}],\"name\":\"notarize\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"previousOwner\",\"type\":\"address\"}],\"name\":\"OwnershipRenounced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"}]" // NotaryBin is the compiled bytecode used for deploying new contracts. -const NotaryBin = `0x608060405234801561001057600080fd5b50610522806100206000396000f3006080604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166301e64725811461005b578063e1112648146100f2578063fb1ace341461014b575b600080fd5b34801561006757600080fd5b506100736004356101a6565b6040518080602001838152602001828103825284818151815260200191508051906020019080838360005b838110156100b657818101518382015260200161009e565b50505050905090810190601f1680156100e35780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156100fe57600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261007394369492936024939284019190819084018382808284375094975061024a9650505050505050565b34801561015757600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526101a494369492936024939284019190819084018382808284375094975061037e9650505050505050565b005b6000602081815291815260409081902080548251601f60026000196101006001861615020190931692909204918201859004850281018501909352808352909283919083018282801561023a5780601f1061020f5761010080835404028352916020019161023a565b820191906000526020600020905b81548152906001019060200180831161021d57829003601f168201915b5050505050908060010154905082565b60606000610256610443565b600080856040518082805190602001908083835b602083106102895780518252601f19909201916020918201910161026a565b518151600019602094850361010090810a8201928316921993909316919091179092526040805196909401869003909520885287820198909852958101600020815181546060601f60026001841615909802909b019091169590950498890188900490970287018401825290860187815295969095879550935085929091508401828280156103595780601f1061032e57610100808354040283529160200191610359565b820191906000526020600020905b81548152906001019060200180831161033c57829003601f168201915b5050509183525050600191909101546020918201528151910151909590945092505050565b6000816040518082805190602001908083835b602083106103b05780518252601f199092019160209182019101610391565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181529182905292902060010154919450501591506103fa905057600080fd5b604080518082018252838152426020808301919091526000848152808252929092208151805192939192610431928492019061045b565b50602082015181600101559050505050565b60408051808201909152606081526000602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061049c57805160ff19168380011785556104c9565b828001600101855582156104c9579182015b828111156104c95782518255916020019190600101906104ae565b506104d59291506104d9565b5090565b6104f391905b808211156104d557600081556001016104df565b905600a165627a7a723058202f26cafc2d47e2fe82a1fda2aa083df782fc0d1b534c8ea261ea634441b4403f0029` +const NotaryBin = `0x608060405234801561001057600080fd5b506040516020806107e5833981016040525160008054600160a060020a03909216600160a060020a0319928316331790921691909117905561078e806100576000396000f30060806040526004361061008d5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166301e647258114610092578063715018a6146101295780638da5cb5b14610140578063c0496e5714610171578063c9d3a88514610189578063e1112648146101b0578063f2fde38b14610209578063fb1ace341461022a575b600080fd5b34801561009e57600080fd5b506100aa600435610276565b6040518080602001838152602001828103825284818151815260200191508051906020019080838360005b838110156100ed5781810151838201526020016100d5565b50505050905090810190601f16801561011a5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561013557600080fd5b5061013e610318565b005b34801561014c57600080fd5b50610155610384565b60408051600160a060020a039092168252519081900360200190f35b34801561017d57600080fd5b5061013e600435610393565b34801561019557600080fd5b5061019e6103af565b60408051918252519081900360200190f35b3480156101bc57600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526100aa9436949293602493928401919081908401838280828437509497506103b59650505050505050565b34801561021557600080fd5b5061013e600160a060020a03600435166104ea565b6040805160206004803580820135601f810184900484028501840190955284845261013e94369492936024939284019190819084018382808284375094975061050d9650505050505050565b60016020818152600092835260409283902080548451600294821615610100026000190190911693909304601f81018390048302840183019094528383529283918301828280156103085780601f106102dd57610100808354040283529160200191610308565b820191906000526020600020905b8154815290600101906020018083116102eb57829003601f168201915b5050505050908060010154905082565b600054600160a060020a0316331461032f57600080fd5b60008054604051600160a060020a03909116917ff8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c6482091a26000805473ffffffffffffffffffffffffffffffffffffffff19169055565b600054600160a060020a031681565b600054600160a060020a031633146103aa57600080fd5b600255565b60025481565b606060006103c16106af565b60016000856040518082805190602001908083835b602083106103f55780518252601f1990920191602091820191016103d6565b518151600019602094850361010090810a8201928316921993909316919091179092526040805196909401869003909520885287820198909852958101600020815181546060601f60026001841615909802909b019091169590950498890188900490970287018401825290860187815295969095879550935085929091508401828280156104c55780601f1061049a576101008083540402835291602001916104c5565b820191906000526020600020905b8154815290600101906020018083116104a857829003601f168201915b5050509183525050600191909101546020918201528151910151909590945092505050565b600054600160a060020a0316331461050157600080fd5b61050a81610632565b50565b60025460009034101561051f57600080fd5b816040518082805190602001908083835b6020831061054f5780518252601f199092019160209182019101610530565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181526001928390529390932001549194505015915061059a905057600080fd5b600054600160a060020a0316156105e85760008054604051600160a060020a0390911691303180156108fc02929091818181858888f193505050501580156105e6573d6000803e3d6000fd5b505b6040805180820182528381524260208083019190915260008481526001825292909220815180519293919261062092849201906106c7565b50602082015181600101559050505050565b600160a060020a038116151561064757600080fd5b60008054604051600160a060020a03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b60408051808201909152606081526000602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061070857805160ff1916838001178555610735565b82800160010185558215610735579182015b8281111561073557825182559160200191906001019061071a565b50610741929150610745565b5090565b61075f91905b80821115610741576000815560010161074b565b905600a165627a7a7230582001b0252bf7f25e941fd126beef7b2b40c7c9922b862a8bd543807bd32f2cf4900029` // DeployNotary deploys a new Ethereum contract, binding an instance of Notary to it. -func DeployNotary(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Notary, error) { +func DeployNotary(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *Notary, error) { parsed, err := abi.JSON(strings.NewReader(NotaryABI)) if err != nil { return common.Address{}, nil, nil, err } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(NotaryBin), backend) + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(NotaryBin), backend, _owner) if err != nil { return common.Address{}, nil, nil, err } @@ -174,6 +176,58 @@ func (_Notary *NotaryTransactorRaw) Transact(opts *bind.TransactOpts, method str return _Notary.Contract.contract.Transact(opts, method, params...) } +// NotarisationFee is a free data retrieval call binding the contract method 0xc9d3a885. +// +// Solidity: function notarisationFee() constant returns(uint256) +func (_Notary *NotaryCaller) NotarisationFee(opts *bind.CallOpts) (*big.Int, error) { + var ( + ret0 = new(*big.Int) + ) + out := ret0 + err := _Notary.contract.Call(opts, out, "notarisationFee") + return *ret0, err +} + +// NotarisationFee is a free data retrieval call binding the contract method 0xc9d3a885. +// +// Solidity: function notarisationFee() constant returns(uint256) +func (_Notary *NotarySession) NotarisationFee() (*big.Int, error) { + return _Notary.Contract.NotarisationFee(&_Notary.CallOpts) +} + +// NotarisationFee is a free data retrieval call binding the contract method 0xc9d3a885. +// +// Solidity: function notarisationFee() constant returns(uint256) +func (_Notary *NotaryCallerSession) NotarisationFee() (*big.Int, error) { + return _Notary.Contract.NotarisationFee(&_Notary.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() constant returns(address) +func (_Notary *NotaryCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var ( + ret0 = new(common.Address) + ) + out := ret0 + err := _Notary.contract.Call(opts, out, "owner") + return *ret0, err +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() constant returns(address) +func (_Notary *NotarySession) Owner() (common.Address, error) { + return _Notary.Contract.Owner(&_Notary.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() constant returns(address) +func (_Notary *NotaryCallerSession) Owner() (common.Address, error) { + return _Notary.Contract.Owner(&_Notary.CallOpts) +} + // Record is a free data retrieval call binding the contract method 0xe1112648. // // Solidity: function record(_notarisedData bytes) constant returns(bytes, uint256) @@ -261,11 +315,347 @@ func (_Notary *NotaryTransactorSession) Notarize(_record []byte) (*types.Transac return _Notary.Contract.Notarize(&_Notary.TransactOpts, _record) } +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Notary *NotaryTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Notary.contract.Transact(opts, "renounceOwnership") +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Notary *NotarySession) RenounceOwnership() (*types.Transaction, error) { + return _Notary.Contract.RenounceOwnership(&_Notary.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Notary *NotaryTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _Notary.Contract.RenounceOwnership(&_Notary.TransactOpts) +} + +// SetNotarisationFee is a paid mutator transaction binding the contract method 0xc0496e57. +// +// Solidity: function setNotarisationFee(_fee uint256) returns() +func (_Notary *NotaryTransactor) SetNotarisationFee(opts *bind.TransactOpts, _fee *big.Int) (*types.Transaction, error) { + return _Notary.contract.Transact(opts, "setNotarisationFee", _fee) +} + +// SetNotarisationFee is a paid mutator transaction binding the contract method 0xc0496e57. +// +// Solidity: function setNotarisationFee(_fee uint256) returns() +func (_Notary *NotarySession) SetNotarisationFee(_fee *big.Int) (*types.Transaction, error) { + return _Notary.Contract.SetNotarisationFee(&_Notary.TransactOpts, _fee) +} + +// SetNotarisationFee is a paid mutator transaction binding the contract method 0xc0496e57. +// +// Solidity: function setNotarisationFee(_fee uint256) returns() +func (_Notary *NotaryTransactorSession) SetNotarisationFee(_fee *big.Int) (*types.Transaction, error) { + return _Notary.Contract.SetNotarisationFee(&_Notary.TransactOpts, _fee) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(_newOwner address) returns() +func (_Notary *NotaryTransactor) TransferOwnership(opts *bind.TransactOpts, _newOwner common.Address) (*types.Transaction, error) { + return _Notary.contract.Transact(opts, "transferOwnership", _newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(_newOwner address) returns() +func (_Notary *NotarySession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { + return _Notary.Contract.TransferOwnership(&_Notary.TransactOpts, _newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(_newOwner address) returns() +func (_Notary *NotaryTransactorSession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { + return _Notary.Contract.TransferOwnership(&_Notary.TransactOpts, _newOwner) +} + +// NotaryOwnershipRenouncedIterator is returned from FilterOwnershipRenounced and is used to iterate over the raw logs and unpacked data for OwnershipRenounced events raised by the Notary contract. +type NotaryOwnershipRenouncedIterator struct { + Event *NotaryOwnershipRenounced // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NotaryOwnershipRenouncedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NotaryOwnershipRenounced) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NotaryOwnershipRenounced) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NotaryOwnershipRenouncedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NotaryOwnershipRenouncedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NotaryOwnershipRenounced represents a OwnershipRenounced event raised by the Notary contract. +type NotaryOwnershipRenounced struct { + PreviousOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipRenounced is a free log retrieval operation binding the contract event 0xf8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c64820. +// +// Solidity: e OwnershipRenounced(previousOwner indexed address) +func (_Notary *NotaryFilterer) FilterOwnershipRenounced(opts *bind.FilterOpts, previousOwner []common.Address) (*NotaryOwnershipRenouncedIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + + logs, sub, err := _Notary.contract.FilterLogs(opts, "OwnershipRenounced", previousOwnerRule) + if err != nil { + return nil, err + } + return &NotaryOwnershipRenouncedIterator{contract: _Notary.contract, event: "OwnershipRenounced", logs: logs, sub: sub}, nil +} + +// WatchOwnershipRenounced is a free log subscription operation binding the contract event 0xf8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c64820. +// +// Solidity: e OwnershipRenounced(previousOwner indexed address) +func (_Notary *NotaryFilterer) WatchOwnershipRenounced(opts *bind.WatchOpts, sink chan<- *NotaryOwnershipRenounced, previousOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + + logs, sub, err := _Notary.contract.WatchLogs(opts, "OwnershipRenounced", previousOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NotaryOwnershipRenounced) + if err := _Notary.contract.UnpackLog(event, "OwnershipRenounced", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// NotaryOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Notary contract. +type NotaryOwnershipTransferredIterator struct { + Event *NotaryOwnershipTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *NotaryOwnershipTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(NotaryOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(NotaryOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *NotaryOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NotaryOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NotaryOwnershipTransferred represents a OwnershipTransferred event raised by the Notary contract. +type NotaryOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: e OwnershipTransferred(previousOwner indexed address, newOwner indexed address) +func (_Notary *NotaryFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*NotaryOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Notary.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &NotaryOwnershipTransferredIterator{contract: _Notary.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: e OwnershipTransferred(previousOwner indexed address, newOwner indexed address) +func (_Notary *NotaryFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *NotaryOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Notary.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(NotaryOwnershipTransferred) + if err := _Notary.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + // NotaryMultiABI is the input ABI used to generate the binding from. -const NotaryMultiABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_firstRecord\",\"type\":\"bytes\"},{\"name\":\"_secondRecord\",\"type\":\"bytes\"}],\"name\":\"notarizeTwo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"notary\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_notary\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]" +const NotaryMultiABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_firstRecord\",\"type\":\"bytes\"},{\"name\":\"_secondRecord\",\"type\":\"bytes\"}],\"name\":\"notarizeTwo\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"notaryFee\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"notary\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_notary\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]" // NotaryMultiBin is the compiled bytecode used for deploying new contracts. -const NotaryMultiBin = `0x608060405234801561001057600080fd5b5060405160208061039d833981016040525160008054600160a060020a03909216600160a060020a031990921691909117905561034b806100526000396000f30060806040526004361061004b5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630926778581146100505780639d54c79d146100e9575b600080fd5b34801561005c57600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526100e794369492936024939284019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a9998810197919650918201945092508291508401838280828437509497506101279650505050505050565b005b3480156100f557600080fd5b506100fe610303565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b600080546040517ffb1ace3400000000000000000000000000000000000000000000000000000000815260206004820181815286516024840152865173ffffffffffffffffffffffffffffffffffffffff9094169463fb1ace34948894929384936044019290860191908190849084905b838110156101b0578181015183820152602001610198565b50505050905090810190601f1680156101dd5780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b1580156101fc57600080fd5b505af1158015610210573d6000803e3d6000fd5b5050600080546040517ffb1ace3400000000000000000000000000000000000000000000000000000000815260206004820181815287516024840152875173ffffffffffffffffffffffffffffffffffffffff909416965063fb1ace349550879490938493604401928601918190849084905b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b1580156102e757600080fd5b505af11580156102fb573d6000803e3d6000fd5b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a7230582067c4bd5c4a01e384e114aa1703b959f06b936b1861ad7cc7548b8f3d018807130029` +const NotaryMultiBin = `0x608060405234801561001057600080fd5b5060405160208061047d833981016040525160008054600160a060020a03909216600160a060020a031990921691909117905561042b806100526000396000f3006080604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166309267785811461005b578063835c853b146100e75780639d54c79d1461010e575b600080fd5b6040805160206004803580820135601f81018490048402850184019095528484526100e594369492936024939284019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a99988101979196509182019450925082915084018382808284375094975061014c9650505050505050565b005b3480156100f357600080fd5b506100fc610328565b60408051918252519081900360200190f35b34801561011a57600080fd5b506101236103e3565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b600080546040517ffb1ace3400000000000000000000000000000000000000000000000000000000815260206004820181815286516024840152865173ffffffffffffffffffffffffffffffffffffffff9094169463fb1ace34948894929384936044019290860191908190849084905b838110156101d55781810151838201526020016101bd565b50505050905090810190601f1680156102025780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b15801561022157600080fd5b505af1158015610235573d6000803e3d6000fd5b5050600080546040517ffb1ace3400000000000000000000000000000000000000000000000000000000815260206004820181815287516024840152875173ffffffffffffffffffffffffffffffffffffffff909416965063fb1ace349550879490938493604401928601918190849084905b838110156102c05781810151838201526020016102a8565b50505050905090810190601f1680156102ed5780820380516001836020036101000a031916815260200191505b5092505050600060405180830381600087803b15801561030c57600080fd5b505af1158015610320573d6000803e3d6000fd5b505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c9d3a8856040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156103af57600080fd5b505af11580156103c3573d6000803e3d6000fd5b505050506040513d60208110156103d957600080fd5b5051600202905090565b60005473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a7230582069c7b45b3c6de0d2511a2b2d5d56868ed00f9c9ba5582d5907c57c67f90b4f620029` // DeployNotaryMulti deploys a new Ethereum contract, binding an instance of NotaryMulti to it. func DeployNotaryMulti(auth *bind.TransactOpts, backend bind.ContractBackend, _notary common.Address) (common.Address, *types.Transaction, *NotaryMulti, error) { @@ -448,6 +838,32 @@ func (_NotaryMulti *NotaryMultiCallerSession) Notary() (common.Address, error) { return _NotaryMulti.Contract.Notary(&_NotaryMulti.CallOpts) } +// NotaryFee is a free data retrieval call binding the contract method 0x835c853b. +// +// Solidity: function notaryFee() constant returns(uint256) +func (_NotaryMulti *NotaryMultiCaller) NotaryFee(opts *bind.CallOpts) (*big.Int, error) { + var ( + ret0 = new(*big.Int) + ) + out := ret0 + err := _NotaryMulti.contract.Call(opts, out, "notaryFee") + return *ret0, err +} + +// NotaryFee is a free data retrieval call binding the contract method 0x835c853b. +// +// Solidity: function notaryFee() constant returns(uint256) +func (_NotaryMulti *NotaryMultiSession) NotaryFee() (*big.Int, error) { + return _NotaryMulti.Contract.NotaryFee(&_NotaryMulti.CallOpts) +} + +// NotaryFee is a free data retrieval call binding the contract method 0x835c853b. +// +// Solidity: function notaryFee() constant returns(uint256) +func (_NotaryMulti *NotaryMultiCallerSession) NotaryFee() (*big.Int, error) { + return _NotaryMulti.Contract.NotaryFee(&_NotaryMulti.CallOpts) +} + // NotarizeTwo is a paid mutator transaction binding the contract method 0x09267785. // // Solidity: function notarizeTwo(_firstRecord bytes, _secondRecord bytes) returns() @@ -468,3 +884,505 @@ func (_NotaryMulti *NotaryMultiSession) NotarizeTwo(_firstRecord []byte, _second func (_NotaryMulti *NotaryMultiTransactorSession) NotarizeTwo(_firstRecord []byte, _secondRecord []byte) (*types.Transaction, error) { return _NotaryMulti.Contract.NotarizeTwo(&_NotaryMulti.TransactOpts, _firstRecord, _secondRecord) } + +// OwnableABI is the input ABI used to generate the binding from. +const OwnableABI = "[{\"constant\":false,\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"previousOwner\",\"type\":\"address\"}],\"name\":\"OwnershipRenounced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"}]" + +// OwnableBin is the compiled bytecode used for deploying new contracts. +const OwnableBin = `0x608060405234801561001057600080fd5b5060008054600160a060020a0319163317905561020b806100326000396000f3006080604052600436106100565763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663715018a6811461005b5780638da5cb5b14610072578063f2fde38b146100a3575b600080fd5b34801561006757600080fd5b506100706100c4565b005b34801561007e57600080fd5b50610087610130565b60408051600160a060020a039092168252519081900360200190f35b3480156100af57600080fd5b50610070600160a060020a036004351661013f565b600054600160a060020a031633146100db57600080fd5b60008054604051600160a060020a03909116917ff8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c6482091a26000805473ffffffffffffffffffffffffffffffffffffffff19169055565b600054600160a060020a031681565b600054600160a060020a0316331461015657600080fd5b61015f81610162565b50565b600160a060020a038116151561017757600080fd5b60008054604051600160a060020a03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03929092169190911790555600a165627a7a72305820939090677929d52a8b7fcd09005569e1345b68565d3dee73b40c555b2f7d4d300029` + +// DeployOwnable deploys a new Ethereum contract, binding an instance of Ownable to it. +func DeployOwnable(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Ownable, error) { + parsed, err := abi.JSON(strings.NewReader(OwnableABI)) + if err != nil { + return common.Address{}, nil, nil, err + } + address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(OwnableBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Ownable{OwnableCaller: OwnableCaller{contract: contract}, OwnableTransactor: OwnableTransactor{contract: contract}, OwnableFilterer: OwnableFilterer{contract: contract}}, nil +} + +// Ownable is an auto generated Go binding around an Ethereum contract. +type Ownable struct { + OwnableCaller // Read-only binding to the contract + OwnableTransactor // Write-only binding to the contract + OwnableFilterer // Log filterer for contract events +} + +// OwnableCaller is an auto generated read-only Go binding around an Ethereum contract. +type OwnableCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// OwnableTransactor is an auto generated write-only Go binding around an Ethereum contract. +type OwnableTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// OwnableFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type OwnableFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// OwnableSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type OwnableSession struct { + Contract *Ownable // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// OwnableCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type OwnableCallerSession struct { + Contract *OwnableCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// OwnableTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type OwnableTransactorSession struct { + Contract *OwnableTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// OwnableRaw is an auto generated low-level Go binding around an Ethereum contract. +type OwnableRaw struct { + Contract *Ownable // Generic contract binding to access the raw methods on +} + +// OwnableCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type OwnableCallerRaw struct { + Contract *OwnableCaller // Generic read-only contract binding to access the raw methods on +} + +// OwnableTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type OwnableTransactorRaw struct { + Contract *OwnableTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewOwnable creates a new instance of Ownable, bound to a specific deployed contract. +func NewOwnable(address common.Address, backend bind.ContractBackend) (*Ownable, error) { + contract, err := bindOwnable(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Ownable{OwnableCaller: OwnableCaller{contract: contract}, OwnableTransactor: OwnableTransactor{contract: contract}, OwnableFilterer: OwnableFilterer{contract: contract}}, nil +} + +// NewOwnableCaller creates a new read-only instance of Ownable, bound to a specific deployed contract. +func NewOwnableCaller(address common.Address, caller bind.ContractCaller) (*OwnableCaller, error) { + contract, err := bindOwnable(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &OwnableCaller{contract: contract}, nil +} + +// NewOwnableTransactor creates a new write-only instance of Ownable, bound to a specific deployed contract. +func NewOwnableTransactor(address common.Address, transactor bind.ContractTransactor) (*OwnableTransactor, error) { + contract, err := bindOwnable(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &OwnableTransactor{contract: contract}, nil +} + +// NewOwnableFilterer creates a new log filterer instance of Ownable, bound to a specific deployed contract. +func NewOwnableFilterer(address common.Address, filterer bind.ContractFilterer) (*OwnableFilterer, error) { + contract, err := bindOwnable(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &OwnableFilterer{contract: contract}, nil +} + +// bindOwnable binds a generic wrapper to an already deployed contract. +func bindOwnable(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(OwnableABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Ownable *OwnableRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _Ownable.Contract.OwnableCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Ownable *OwnableRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Ownable.Contract.OwnableTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Ownable *OwnableRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Ownable.Contract.OwnableTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Ownable *OwnableCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _Ownable.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Ownable *OwnableTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Ownable.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Ownable *OwnableTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Ownable.Contract.contract.Transact(opts, method, params...) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() constant returns(address) +func (_Ownable *OwnableCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var ( + ret0 = new(common.Address) + ) + out := ret0 + err := _Ownable.contract.Call(opts, out, "owner") + return *ret0, err +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() constant returns(address) +func (_Ownable *OwnableSession) Owner() (common.Address, error) { + return _Ownable.Contract.Owner(&_Ownable.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() constant returns(address) +func (_Ownable *OwnableCallerSession) Owner() (common.Address, error) { + return _Ownable.Contract.Owner(&_Ownable.CallOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Ownable *OwnableTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Ownable.contract.Transact(opts, "renounceOwnership") +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Ownable *OwnableSession) RenounceOwnership() (*types.Transaction, error) { + return _Ownable.Contract.RenounceOwnership(&_Ownable.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Ownable *OwnableTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _Ownable.Contract.RenounceOwnership(&_Ownable.TransactOpts) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(_newOwner address) returns() +func (_Ownable *OwnableTransactor) TransferOwnership(opts *bind.TransactOpts, _newOwner common.Address) (*types.Transaction, error) { + return _Ownable.contract.Transact(opts, "transferOwnership", _newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(_newOwner address) returns() +func (_Ownable *OwnableSession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { + return _Ownable.Contract.TransferOwnership(&_Ownable.TransactOpts, _newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(_newOwner address) returns() +func (_Ownable *OwnableTransactorSession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { + return _Ownable.Contract.TransferOwnership(&_Ownable.TransactOpts, _newOwner) +} + +// OwnableOwnershipRenouncedIterator is returned from FilterOwnershipRenounced and is used to iterate over the raw logs and unpacked data for OwnershipRenounced events raised by the Ownable contract. +type OwnableOwnershipRenouncedIterator struct { + Event *OwnableOwnershipRenounced // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OwnableOwnershipRenouncedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OwnableOwnershipRenounced) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OwnableOwnershipRenounced) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OwnableOwnershipRenouncedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OwnableOwnershipRenouncedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OwnableOwnershipRenounced represents a OwnershipRenounced event raised by the Ownable contract. +type OwnableOwnershipRenounced struct { + PreviousOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipRenounced is a free log retrieval operation binding the contract event 0xf8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c64820. +// +// Solidity: e OwnershipRenounced(previousOwner indexed address) +func (_Ownable *OwnableFilterer) FilterOwnershipRenounced(opts *bind.FilterOpts, previousOwner []common.Address) (*OwnableOwnershipRenouncedIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + + logs, sub, err := _Ownable.contract.FilterLogs(opts, "OwnershipRenounced", previousOwnerRule) + if err != nil { + return nil, err + } + return &OwnableOwnershipRenouncedIterator{contract: _Ownable.contract, event: "OwnershipRenounced", logs: logs, sub: sub}, nil +} + +// WatchOwnershipRenounced is a free log subscription operation binding the contract event 0xf8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c64820. +// +// Solidity: e OwnershipRenounced(previousOwner indexed address) +func (_Ownable *OwnableFilterer) WatchOwnershipRenounced(opts *bind.WatchOpts, sink chan<- *OwnableOwnershipRenounced, previousOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + + logs, sub, err := _Ownable.contract.WatchLogs(opts, "OwnershipRenounced", previousOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OwnableOwnershipRenounced) + if err := _Ownable.contract.UnpackLog(event, "OwnershipRenounced", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// OwnableOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Ownable contract. +type OwnableOwnershipTransferredIterator struct { + Event *OwnableOwnershipTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OwnableOwnershipTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OwnableOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OwnableOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OwnableOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OwnableOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OwnableOwnershipTransferred represents a OwnershipTransferred event raised by the Ownable contract. +type OwnableOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: e OwnershipTransferred(previousOwner indexed address, newOwner indexed address) +func (_Ownable *OwnableFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*OwnableOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Ownable.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &OwnableOwnershipTransferredIterator{contract: _Ownable.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: e OwnershipTransferred(previousOwner indexed address, newOwner indexed address) +func (_Ownable *OwnableFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *OwnableOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Ownable.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OwnableOwnershipTransferred) + if err := _Ownable.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} From 1ed8f4f5e44febb1104cec686769730fdace7353 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Thu, 27 Sep 2018 19:29:52 -0700 Subject: [PATCH 33/38] [panthalassa] added tx fee to notary --- mobile_interface.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile_interface.go b/mobile_interface.go index b4a5dd7..02fa65d 100644 --- a/mobile_interface.go +++ b/mobile_interface.go @@ -167,7 +167,7 @@ func start(dbDir string, km *keyManager.KeyManager, config StartConfig, client, } // rinkeby addresses - notaryMultiAddr = common.HexToAddress("0x5e04e983bb438d70471848d7f24416fa0a9a7de1") + notaryMultiAddr = common.HexToAddress("0xe4d2032fdda10d4e6f483e2dea6857abc0e3cbf8") notaryContract, err := documents.NewNotaryMulti(notaryMultiAddr, ethClient) if err != nil { From 6b8d026891c7039adc188a39c699b56b98e33963 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Thu, 27 Sep 2018 22:35:46 -0700 Subject: [PATCH 34/38] [panthalassa] fixed chat storage nil bug --- documents/call.go | 6 +++--- mobile_interface.go | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/documents/call.go b/documents/call.go index ea058d2..9af1a38 100644 --- a/documents/call.go +++ b/documents/call.go @@ -229,16 +229,16 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int if err := d.s.db.One("ID", int(docID), &doc); err != nil { return map[string]interface{}{}, err } - + // decrypt document content docContent, err := d.km.AESDecrypt(doc.EncryptedContent) if err != nil { return map[string]interface{}{}, err } - + // assign plain document content doc.Content = docContent - + // hash document docHash, err := mh.Sum(doc.Content, mh.SHA2_256, -1) if err != nil { diff --git a/mobile_interface.go b/mobile_interface.go index a8fcbb3..a11f3a8 100644 --- a/mobile_interface.go +++ b/mobile_interface.go @@ -195,6 +195,7 @@ func start(dbDir string, km *keyManager.KeyManager, config StartConfig, client, db: dbInstance, dAppStorage: dAppStorage, dyncall: dcr, + chatDB: chatStorage, } return nil From 7ee01548217cd5ddfb083c8f77ff751ce08e192c Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Thu, 27 Sep 2018 22:40:18 -0700 Subject: [PATCH 35/38] [chat] added sender field --- chat.go | 1 + 1 file changed, 1 insertion(+) diff --git a/chat.go b/chat.go index 9922319..3d5ecf0 100644 --- a/chat.go +++ b/chat.go @@ -172,6 +172,7 @@ func Messages(chatID int, startStr string, amount int) (string, error) { "created_at": msg.CreatedAt, "received": msg.Received, "dapp": dapp, + "sender": msg.Sender, }) } From 30486115ee4432feea96cae890b0b2379f7540e7 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Thu, 27 Sep 2018 23:52:22 -0700 Subject: [PATCH 36/38] [docs] fixed decryption --- documents/call.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/documents/call.go b/documents/call.go index 29f7855..51c36a2 100644 --- a/documents/call.go +++ b/documents/call.go @@ -226,22 +226,23 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int if err := d.s.db.One("ID", int(docID), &doc); err != nil { return map[string]interface{}{}, err } - - // hash document - docHash, err := mh.Sum(doc.Content, mh.SHA2_256, -1) - if err != nil { - return map[string]interface{}{}, err - } - + // decrypt document content docContent, err := d.km.AESDecrypt(doc.EncryptedContent) if err != nil { return map[string]interface{}{}, err } - + // assign plain document content doc.Content = docContent - + + + // hash document + docHash, err := mh.Sum(doc.Content, mh.SHA2_256, -1) + if err != nil { + return map[string]interface{}{}, err + } + docContentCID := cid.NewCidV1(cid.Raw, docHash).Bytes() // attach cid to document From c7a865c3ca3e7ea4c9de37b6c2252bd04f460381 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Fri, 28 Sep 2018 08:32:37 -0700 Subject: [PATCH 37/38] [tests] fixed api test --- api/dapp.go | 5 +++-- bip32/bip32_test.go | 8 ++++---- db/bolt_to_storm.go | 1 - documents/call.go | 9 ++++----- keyManager/keyManager.go | 2 +- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/api/dapp.go b/api/dapp.go index 1c92ada..aa03883 100644 --- a/api/dapp.go +++ b/api/dapp.go @@ -66,15 +66,16 @@ func (a *DAppApi) SendEthereumTransaction(value, to, data string) (string, error objTx := map[string]interface{}{ "nonce": ethTx.Nonce, "gasPrice": ethTx.GasPrice, - "gas": ethTx.GasLimit, + "gasLimit": ethTx.GasLimit, "to": ethTx.To, "value": ethTx.Value, - "input": ethTx.Data, + "data": ethTx.Data, "v": ethTx.V, "r": ethTx.R, "s": ethTx.S, "from": ethTx.From, "hash": ethTx.Hash, + "chainId": ethTx.ChainID, } raw, err := json.Marshal(objTx) diff --git a/bip32/bip32_test.go b/bip32/bip32_test.go index 3bd6422..223c6c5 100644 --- a/bip32/bip32_test.go +++ b/bip32/bip32_test.go @@ -132,10 +132,10 @@ func TestKeyDerivation(t *testing.T) { //Test vector set one testVectorErrorMapping := map[string]int{ - "m/0H/1": 1, - "m/0H/1/2H": 1, - "m/0H/1/2H/2": 1, - "m/0H/1/2H/2/1000000000": 1, + "m/0H/1": 1, + "m/0H/1/2H": 1, + "m/0H/1/2H/2": 1, + "m/0H/1/2H/2/1000000000": 1, "m/0": 0, "m/0/2147483647H": 0, "m/0/2147483647H/1": 0, diff --git a/db/bolt_to_storm.go b/db/bolt_to_storm.go index 978c490..e083294 100644 --- a/db/bolt_to_storm.go +++ b/db/bolt_to_storm.go @@ -6,7 +6,6 @@ import ( "errors" "time" - aes "github.com/Bit-Nation/panthalassa/crypto/aes" keyManager "github.com/Bit-Nation/panthalassa/keyManager" queue "github.com/Bit-Nation/panthalassa/queue" diff --git a/documents/call.go b/documents/call.go index 51c36a2..336f3e5 100644 --- a/documents/call.go +++ b/documents/call.go @@ -226,23 +226,22 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int if err := d.s.db.One("ID", int(docID), &doc); err != nil { return map[string]interface{}{}, err } - + // decrypt document content docContent, err := d.km.AESDecrypt(doc.EncryptedContent) if err != nil { return map[string]interface{}{}, err } - + // assign plain document content doc.Content = docContent - - + // hash document docHash, err := mh.Sum(doc.Content, mh.SHA2_256, -1) if err != nil { return map[string]interface{}{}, err } - + docContentCID := cid.NewCidV1(cid.Raw, docHash).Bytes() // attach cid to document diff --git a/keyManager/keyManager.go b/keyManager/keyManager.go index d3407a2..bd3aefa 100644 --- a/keyManager/keyManager.go +++ b/keyManager/keyManager.go @@ -328,7 +328,7 @@ func (km KeyManager) SignEthTx(signer types.Signer, addresses common.Address, tx } // convert gas - txMap["gas"], err = numToHex(txMap, "gas") + txMap["gas"], err = numToHex(txMap, "gasLimit") if err != nil { return nil, err } From 36206a49d741020826f7b2abe5cffd123c795d87 Mon Sep 17 00:00:00 2001 From: Florian Lenz Date: Fri, 28 Sep 2018 11:55:30 -0700 Subject: [PATCH 38/38] [docs] fixed call to notarize document --- documents/call.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/documents/call.go b/documents/call.go index 336f3e5..35c2bc9 100644 --- a/documents/call.go +++ b/documents/call.go @@ -5,11 +5,13 @@ import ( "errors" "time" + "fmt" keyManager "github.com/Bit-Nation/panthalassa/keyManager" bind "github.com/ethereum/go-ethereum/accounts/abi/bind" common "github.com/ethereum/go-ethereum/common" cid "github.com/ipfs/go-cid" mh "github.com/multiformats/go-multihash" + "math/big" ) type DocumentCreateCall struct { @@ -266,12 +268,15 @@ func (d *DocumentSubmitCall) Handle(data map[string]interface{}) (map[string]int if err != nil { return nil, err } - + fmt.Println(docContentCID) + fmt.Println(cidSignature) // submit tx to chain tx, err := d.n.NotarizeTwo(&bind.TransactOpts{ - From: common.HexToAddress(ethAddr), - Signer: d.km.SignEthTx, - Value: notaryFee, + From: common.HexToAddress(ethAddr), + Signer: d.km.SignEthTx, + Value: notaryFee, + GasLimit: 500000, + GasPrice: big.NewInt(50000000000), }, docContentCID, cidSignature) if err != nil { return map[string]interface{}{}, err