Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • monero-project/ccs-back
  • xiphon/ccs-back
  • Fudin/ccs-back
  • john_r365/ccs-back
  • plowsofff/ccs-back
5 results
Show changes
......@@ -63,7 +63,7 @@ class Wallet
}
$transactions = [];
const toScan = ['pool', 'in'];
const toScan = ['pool', 'in'];
foreach (toScan as $entry) {
if (!isset($response[$entry])) {
continue;
......@@ -72,6 +72,9 @@ class Wallet
if $payment['subaddr_index']['major'] != $account_index {
continue;
}
if ($payment['locked']) {
continue;
}
$transaction = new Transaction(
$payment['txid'],
$payment['amount'],
......
<?php
namespace Monero;
interface WalletCommon
{
public static function digitsAfterTheRadixPoint() : int;
public function getPaymentAddress();
public function scanIncomingTransfers($min_height = 0);
public function blockHeight() : int;
public function createQrCodeString($address, $amount = null) : string;
}
......@@ -6,8 +6,13 @@ use App\Project;
use Carbon\Carbon;
use Illuminate\Support\Collection;
class WalletOld
class WalletOld implements WalletCommon
{
public static function digitsAfterTheRadixPoint() : int
{
return 12;
}
/**
* WalletOld constructor.
*
......@@ -15,7 +20,9 @@ class WalletOld
*/
public function __construct($client = null)
{
$this->client = $client ?: new jsonRPCClient(env('RPC_URL'));
$this->client = $client ?: new jsonRPCClient([ 'username' => env('RPC_USER'),
'password' => env('RPC_PASSWORD'),
'url' => env('RPC_URL')]);
}
/**
......@@ -68,6 +75,9 @@ class WalletOld
if ($payment['subaddr_index']['major'] != $account_index) {
continue;
}
if ($payment['locked']) {
continue;
}
$transaction = new Transaction(
$payment['txid'],
$payment['amount'],
......@@ -90,7 +100,7 @@ class WalletOld
*
* @return int
*/
public function blockHeight()
public function blockHeight() : int
{
return $this->client->blockHeight();
}
......
<?php
namespace Monero;
use Carbon\Carbon;
class WalletZcoin implements WalletCommon
{
private $rpc;
public static function digitsAfterTheRadixPoint() : int
{
return 8;
}
public function __construct()
{
$this->rpc = new jsonRpcBase([ 'auth_type' => 'basic',
'username' => env('RPC_USER'),
'password' => env('RPC_PASSWORD'),
'url' => env('RPC_URL')]);
}
public function getPaymentAddress()
{
return ['address' => $this->rpc->request('getnewaddress')];
}
private function decodeTxAmount(string $tx_amount) : int
{
$tx_amount = str_replace(',', '.', $tx_amount);
$amount = explode('.', $tx_amount);
if (sizeof($amount) < 1 || sizeof($amount) > 2) {
throw new \Exception('Failed to decode tx amount ' . $tx_amount);
}
$fraction = $amount[1] ?? "";
if (strlen($fraction) > $this->digitsAfterTheRadixPoint()) {
throw new \Exception('Failed to decode tx amount, too many digits after the redix point ' . $tx_amount);
}
$amount = $amount[0] . str_pad($fraction, $this->digitsAfterTheRadixPoint(), '0');
$amount = intval($amount);
if ($amount == 0) {
throw new \Exception('Failed to convert tx amount to int ' . $tx_amount);
}
return $amount;
}
public function scanIncomingTransfers($skip_txes = 0)
{
return collect($this->rpc->request('listtransactions', ['', 100, $skip_txes]))->filter(function ($tx) {
return $tx['category'] == 'receive';
})->map(function ($tx) {
return new Transaction(
$tx['txid'],
$this->decodeTxAmount($tx['amount']),
$tx['address'],
$tx['confirmations'],
0,
Carbon::now(),
0,
isset($tx['blockhash']) ? $this->blockHeightByHash($tx['blockhash']) : 0
);
});
}
public function blockHeight() : int
{
return $this->rpc->request('getblockcount');
}
public function createQrCodeString($address, $amount = null) : string
{
return 'zcoin:' . $address . ($amount ? '?amount=' . $amount : '');
}
private function blockHeightByHash($block_hash) : int
{
return $this->rpc->request('getblockheader', [$block_hash])['height'];
}
}
......@@ -12,18 +12,7 @@ use Illuminate\Support\Facades\Log;
*/
class jsonRPCClient implements Contracts\WalletManager
{
/** @var string */
private $username = 'test2';
/** @var string */
private $password = 'test2';
/** @var string */
private $url = 'http://127.0.0.1:28080/json_rpc';
/** @var Client|null */
private $client;
private $rpc;
/**
* JsonRPCClient constructor.
......@@ -32,20 +21,7 @@ class jsonRPCClient implements Contracts\WalletManager
*/
public function __construct($options, $client = null)
{
$this->username = $options['username'] ?? $this->username;
$this->password = $options['password'] ?? $this->password;
$this->url = $options['url'] ?? $this->url;
if (empty($client)) {
$client = new Client([
'base_uri' => $this->url,
'headers' => [
'Content-Type' => 'application/json',
]
]);
}
$this->client = $client;
$this->rpc = new jsonRpcBase($options, $client);
}
/**
......@@ -55,7 +31,7 @@ class jsonRPCClient implements Contracts\WalletManager
*/
public function balance() : int
{
$response = $this->request('get_balance');
$response = $this->rpc->request('get_balance');
return $response['balance'];
}
......@@ -66,7 +42,7 @@ class jsonRPCClient implements Contracts\WalletManager
*/
public function unlockedBalance() : int
{
$response = $this->request('get_balance');
$response = $this->rpc->request('get_balance');
return $response['unlocked_balance'];
}
......@@ -77,7 +53,7 @@ class jsonRPCClient implements Contracts\WalletManager
*/
public function address() : string
{
$response = $this->request('get_address');
$response = $this->rpc->request('get_address');
return $response['address'];
}
......@@ -88,7 +64,7 @@ class jsonRPCClient implements Contracts\WalletManager
*/
public function blockHeight() : int
{
$response = $this->request('get_height');
$response = $this->rpc->request('get_height');
return $response['height'];
}
......@@ -102,7 +78,7 @@ class jsonRPCClient implements Contracts\WalletManager
*/
public function createSubaddress($account_index = 0, $label = '') : array
{
$response = $this->request('create_address', ['account_index' => $account_index, 'label' => $label]);
$response = $this->rpc->request('create_address', ['account_index' => $account_index, 'label' => $label]);
return $response;
}
......@@ -113,7 +89,7 @@ class jsonRPCClient implements Contracts\WalletManager
*/
public function incomingTransfers($min_height = 0) : array
{
$response = $this->request('get_transfers', ['pool' => true, 'in' => true, 'min_height' => $min_height, 'filter_by_height' => $min_height > 0 ? true : false]);
$response = $this->rpc->request('get_transfers', ['pool' => true, 'in' => true, 'min_height' => $min_height, 'filter_by_height' => $min_height > 0 ? true : false]);
return $response;
}
......@@ -128,7 +104,7 @@ class jsonRPCClient implements Contracts\WalletManager
*/
public function payments($paymentIds, $minHeight) : array
{
$response = $this->request('get_bulk_payments', ['payment_ids' => $paymentIds, 'min_block_height' => $minHeight]);
$response = $this->rpc->request('get_bulk_payments', ['payment_ids' => $paymentIds, 'min_block_height' => $minHeight]);
return $response;
}
......@@ -144,7 +120,7 @@ class jsonRPCClient implements Contracts\WalletManager
*/
public function createUri($address, $amount = null, $paymentId = null) : string
{
$response = $this->request('make_uri', ['address' => $address, 'amount' => $amount, 'payment_id' => $paymentId]);
$response = $this->rpc->request('make_uri', ['address' => $address, 'amount' => $amount, 'payment_id' => $paymentId]);
return $response['uri'];
}
......@@ -158,60 +134,4 @@ class jsonRPCClient implements Contracts\WalletManager
{
return bin2hex(openssl_random_pseudo_bytes(32));
}
/**
* Sets up the request data body
*
* @param string $method name of the rpc command
* @param array $params associative array of variables being passed to the method
*
* @return false|string will return a json string or false
*/
private function preparePayload($method, $params)
{
$payload = [
'jsonrpc' => '2.0',
'id' => '0',
'method' => $method,
'params' => $params,
];
return json_encode($payload);
}
/**
* Send off request to rpc server
*
* @param string $method name of the rpc command
* @param array $params associative array of variables being passed to the method
*
* @return mixed the rpc query result
*
* @throws \RuntimeException
*/
protected function request(string $method, array $params = [])
{
$payload = $this->preparePayload($method, $params);
try {
$response = $this->client->request('POST', '',[
'auth' => [$this->username, $this->password, 'digest'],
'body' => $payload,
'headers' => [
'Content-Type' => 'application/json',
]
]);
$body = $response->getBody();
} catch (GuzzleException $exception) {
Log::error($exception);
throw new \RuntimeException('Connection to node unsuccessful');
}
$result = json_decode((string) $body, true);
if (isset($result['error'])) {
throw new \RuntimeException($result['error']['message']);
}
return $result['result'];
}
}
<?php
namespace Monero;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;
class jsonRpcBase
{
/** @var string */
private $username = 'test2';
/** @var string */
private $password = 'test2';
/** @var string */
private $url = 'http://127.0.0.1:28080/json_rpc';
/** @var Client|null */
private $client;
private $auth_type;
/**
* JsonRPCClient constructor.
* @param array $options
* @param null $client
*/
public function __construct($options, $client = null)
{
$this->username = $options['username'] ?? $this->username;
$this->password = $options['password'] ?? $this->password;
$this->url = $options['url'] ?? $this->url;
$this->auth_type = $options['auth_type'] ?? 'digest';
if (empty($client)) {
$client = new Client([
'base_uri' => $this->url,
'headers' => [
'Content-Type' => 'application/json',
]
]);
}
$this->client = $client;
}
/**
* Sets up the request data body
*
* @param string $method name of the rpc command
* @param array $params associative array of variables being passed to the method
*
* @return false|string will return a json string or false
*/
private function preparePayload($method, $params)
{
$payload = [
'jsonrpc' => '2.0',
'id' => '0',
'method' => $method,
'params' => $params,
];
return json_encode($payload);
}
/**
* Send off request to rpc server
*
* @param string $method name of the rpc command
* @param array $params associative array of variables being passed to the method
*
* @return mixed the rpc query result
*
* @throws \RuntimeException
*/
public function request(string $method, array $params = [])
{
$payload = $this->preparePayload($method, $params);
try {
$response = $this->client->request('POST', '',[
'auth' => [$this->username, $this->password, $this->auth_type],
'body' => $payload,
'headers' => [
'Content-Type' => 'application/json',
]
]);
$body = $response->getBody();
} catch (GuzzleException $exception) {
Log::error($exception);
error_log($exception);
throw new \RuntimeException('Connection to node ' . $this->url . ' unsuccessful');
}
$result = json_decode((string) $body, true);
if (isset($result['error'])) {
throw new \RuntimeException($result['error']['message']);
}
return $result['result'];
}
}
......@@ -15,18 +15,19 @@ php >= 7.1
```
apt update
apt install -y jekyll mysql-server nginx php php-curl php-fpm php-gd php-mbstring php-mysql php-xml unzip
apt install -y cron git jekyll mysql-server nginx php php-curl php-fpm php-gd php-mbstring php-mysql php-xml unzip
```
Install `Composer` following the instructions at https://getcomposer.org/download/
Checkout and configure CCS backend, frontend and proposals repositories (replace `<REPOSITORY_CCS_BACKEND>`, `<REPOSITORY_CCS_FRONTEND>`, `<REPOSITORY_CCS_PROPOSALS>` with the actual URLs)
```
cd /var/www/html
git clone --recursive https://repo.getmonero.org/monero-project/ccs-back.git
git -C ccs-back/storage/app/proposals checkout master
git clone <REPOSITORY_CCS_BACKEND>
git clone <REPOSITORY_CCS_FRONTEND>
git clone <REPOSITORY_CCS_PROPOSALS> ccs-back/storage/app/proposals
git clone https://repo.getmonero.org/monero-project/ccs-front.git
rm -rf ccs-front/proposals
ln -s /var/www/html/ccs-back/storage/app/proposals ccs-front/proposals
ln -fs /var/www/html/ccs-back/storage/app/proposals.json ccs-front/_data/proposals.json
......@@ -37,16 +38,13 @@ composer update
cp .env.example .env
```
Run Monero RPC wallet in background with `--disable-rpc-login` option
Example:
```
./monero-wallet-rpc --wallet-file=wallet --password=secret --disable-rpc-login --rpc-bind-port=28080
```
Spin up MYSQL server, create new database, user and grant user access to it
Open `.env` in editor of choice and edit the following lines:
Open `.env` in editor of choice and edit the following lines:
> `COIN` - choose one of supported coins: `monero` or `zcoin`
> `REPOSITORY_URL` - CCS proposals Github URL or GitLab API endpoint (e.g. https://\<GITLAB_DOMAIN>/api/v4/projects/\<PROJECT_ID>)>
> `GITHUB_ACCESS_TOKEN` - leave empty if you are not using Github or visit https://github.com/settings/tokens to generate new `public_repo` token
```
APP_URL=http://<YOUR_DOMAIN>
APP_URL=http://<HOSTNAME>
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
......@@ -56,8 +54,13 @@ DB_USERNAME=<DB_USER_NAME>
DB_PASSWORD=<DB_USER_PASSWORD>
RPC_URL=http://127.0.0.1:28080/json_rpc
RPC_USER=
RPC_PASSWORD=
COIN=<COIN>
GITLAB_URL=https://repo.getmonero.org/api/v4/projects/54
REPOSITORY_URL=<REPOSITORY_URL>
GITHUB_ACCESS_TOKEN=
```
Initialize the system
......@@ -76,11 +79,11 @@ chown -R www-data ccs-back/
chown -R www-data ccs-front/
```
Remove Nginx example config
Remove Nginx example config
```
rm /etc/nginx/sites-enabled/default
```
Create new file `/etc/nginx/sites-enabled/ccs` in editor of choice and paste the following lines replacing `<IP_ADDRESS>` and `<PHP_VERSION>` with appropriate values
Create new file `/etc/nginx/sites-enabled/ccs` in editor of choice and paste the following lines replacing `<HOSTNAME>` and `<PHP_VERSION>` with appropriate values
```
server {
......@@ -88,15 +91,15 @@ server {
listen [::]:80 default_server;
root /var/www/html/ccs-front/_site/;
index index.php index.html;
server_name <IP_ADDRESS>;
server_name <HOSTNAME>;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# pass the PHP scripts to FastCGI server
#
location ~ \.php$ {
root /var/www/html/ccs-back/public/;
include snippets/fastcgi-php.conf;
......@@ -120,15 +123,19 @@ Instead of scheduling a cron job you can run the following commands in no partic
```
php /var/www/html/ccs-back/artisan proposal:process
php /var/www/html/ccs-back/artisan generate:addresses
php /var/www/html/ccs-back/artisan monero:notify
php /var/www/html/ccs-back/artisan wallet:notify
php /var/www/html/ccs-back/artisan proposal:update
```
3. Process incoming donations
2. Process incoming donations
*Run it either on new block/tx notification or schedule it to run every minute or so*
```
php /var/www/html/ccs-back/artisan monero:notify
```
2. Generate static HTML files
1. Generate static HTML files
```
jekyll build --source /var/www/html/ccs-front --destination /var/www/html/ccs-front/_site
```
2. Get the full list of processed transactions in JSON format
```
php /var/www/html/ccs-back/artisan deposit:list
```
Subproject commit 4459b497ee672bcc7e0848f2da7eed93152e4e06