[LightningNetwork] インボイス

インボイスは支払い指示書
ペイメントID(ペイメントハッシュ)、受取人、金額、オプションなどが含まれる
通常インボイスはbech32エンコードかQRコードとしてエンコードされる
インボイスには請求金額と受取人の署名が含まれる。支払い人はこの署名を使って公開鍵(ノードID)を取得する
LNはインボイスに基づきペイメントを送信
有効期限を設定することもできる

### ペイメントハッシュ
ランダムな数字r
H = sha256(r)

[LightningNetwork] ペイメントチャネル

チャネルパートナーとは2つのノード間の金銭関係、2of2マルチシグの暗号プロトコルによって管理(自分と相手)
チャネルの残高がエンコードされ、その残高をどのように分配するかが定義される
トランザクションシーケンスのトランザクションはスプリクト言語を使う
チャネルを開いた時にコミットされるビットコインの量
チャネル経由で同時に送信できる未実行・実行中のルーティングペイメントの数も制限される
ビットコインブロックチェーンに記録されるのは最終残高のみ

### ファンディングトランザクション
1人がマルチシグアドレスにbitcoinを送金することでペイメントチャネルに資金を預ける
これをchannel capacityと呼ぶ

### チャネルの開き方
2つの公開鍵を使って2of2マルチシグアドレスを作成
払い戻しトランザクションはコミットメントトランザクションと呼ばれる

1. open_channelメッセージでBobに通知
2. accept_channelメッセージでAliceに送信
3. pubkey pubkey 2 CHECKMULTISIGでトランザクションを作成
4. funding_createdでBobに送信
5. コミットメントトランザクションを作成
6. Bobが funding_signedメッセージでAliceに返す
7. 署名交換後にAliceがブロードキャスト

### 古い状態を使った不正
古いコミットメントトランザクションが送信された場合は、罰を与えることができるように作られれている
失効のメカニズム:timelock delayとrevocation secretがペイメントにある
新しいコミットメントの際に、古いコミットメントトランザクションを失効させる
※失効シークレットの管理と格納はLNの最も複雑な部分の1つである

### チャネルを公表・クローズ
チャネルを公表するとルーティング手数料を獲得できる
チャネルを閉じるときはトランザクション手数料がかかる
クローズには相互クローズ、強制クローズ、プロトコル違反などある

LightningNetwork 概要

LNを使うには、ニーズに合ったLNウォレットを選ぶ必要がある
L Eclairウォレットを選択する

ライトニングネットワークノードはウォレットである
他のライトニングノードとP2P方式で通信しなければならない
LNはbitcoin nodeにアクセスし資金を保全する必要がある

ライトニングエクスプローラ
https://1ml.com/
その他にもACINQ, Amboss Space, Fiatjaf, hashXPなどLNエクスプローラがある

### ライトニングウォレット
keystore: secret keyを保持
Lightning Network Node
Bitcoin node
database map: ノードとチャネルのマップ
channel manager: LNチャネルを開閉できるコンポーネント
close-up system: チャネルのパスを調べるコンポーネント
※鍵の管理を外部に委託するウォレットをcustodial walletと呼ぶ。鍵をどのように管理するかでウォレットを選択する。またLN Walletが使うのはfull nodeか第三者のnodeかなどを見極める必要がある
Lightweight, Noneなどはcustodial walletになる。自己管理型かどうかを選択する

Neutrino: ビットコインノードを実行しないwallet, neutrinoプロトコルを使ってアクセス
Electrum: ビットコインノードを実行しないwallet

[bitcoin] ライトニングネットワーク概要

ライトニングネットワークはビットコインの支払いをオフチェーンで実行できるようにするP2Pネットワーク
ビットコインのブロックチェーンにコミットされない、オフチェーンペイメントと呼ぶ
ルーティングネットワークで、支払人から受取人までのパスに沿って各ペイメントチャネルをホップしていく。
LNと略される
ビットコインをベースとしたセカンドレイヤーテクノロジ
チャネルを書き換える1種類のトランザクションにスプライシングと呼ばれるものがあり、チャネルにコミットされている資金を追加または削除に使うことができる
LNの2つのノード間の金銭関係をペイメントチャネルと呼ぶ
ペイメントは送信者から受信者までのパスを辿る1つ以上のペイメントチャネル経由でルーティングされる
LNではビットコイントランザクションを使って資金を移動する

### fairness protocol
互いに信頼していない参加者が公正な結果を得られるようにするためにインセンティブ、ディスインセンティブを利用する
e.g. 2人で均等に分けたい場合は、参加者で分割者と選択者の役割に分ける, hash function, digital signature, encryption/decryption

– チャネルに資金を預けるユーザは、ファンディングトランザクションを公開する前に払い戻しトランザクションが署名されていることを確認する
– チャネルが新しい状態に遷移する度に、誰かが古い状態をブロードキャストしようとしたら残高を全て失って罰を受ける
– ペイメントを転送するユーザは、資金の転送をコミットした場合、1つ前のノードから返金または報酬を受け取れる
– ビットコインを利用するのは最初に読み込む時と、決済(settle)時にビットコインをライトニングから取り出す時のみ。トランザクションは公開されないのでプライベートになる
– LMはThe Onion Routerのオニオンルーティングを使う

SRM452 HamiltonPath

There are N cities in a country, numbered 0 to N-1. Each pair of cities is connected by a bidirectional road.

John plans to travel through the country using the following rules:
He must start in one city and end in another city after travelling exactly N-1 roads.
He must visit each city exactly once.
You are given a String[] roads. If the j-th character of the i-th element of roads is ‘Y’, he must travel the road that connects city i and city j.
For example, if there are three cities, and he wants to travel the road between city 0 and city 1, there are 4 possible paths: 0->1->2, 1->0->2, 2->0->1, 2->1->0. Paths 0->2->1 and 1->2->0 are not allowed because they do not allow him to travel the road between city 0 and city 1.

Return the number of paths he can choose, modulo 1,000,000,007.

#include <string>
#include <vector>
using namespace std;

bool visited[50] = {false};

class HamiltonPath {
    public:
        vector <string> roads;

        int countPaths(vector <string> roads){
            int group=0, free=0;
            int connect[50] = {0};

            long long sum = 1;

            this->roads = roads;

            for(int i=0; i<roads.size(); i++){
                int y = 0;
                for(int j=0; j<roads[i].size(); j++){
                    if(roads[i].substr(j, 1) == "Y"){
                        if( 2 < ++y) return 0;
                    }
                }
                connect[i] = y;
            }

            for (int i = 0; i<roads.size(); i++){
                if(connect[i]==0){
                    visited[i] = true;
                    free++;
                } else if(connect[i] == 1 && !visited[i]){
                    group++;
                    dfs(i);
                }
            }
            for (int i=0; i<roads.size(); i++)
                if(!visited[i]) return 0;
            for (int i=0; i<group+free; i++)
                sum = sum * (i+1) % 100000007;
            for (int i=0; i<group; i++)
                sum = sum * 2 % 100000007;
            return (int)sum;
        }

        void dfs(int city){
            visited[city] = true;
            for(int i=0; i < roads[city].size(); i++){
                if(road[city].substr(i, 1) == "Y" && !visited[i]) dfs(i);
            }
        }
};

SRM443 CirclesCountry

Circles Country is a country that contains several circular-shaped districts. Some districts may be situated inside other districts, but their borders do not intersect or touch. Qatam is a resident of Circles Country. When he travels between two locations, he always tries to cross the fewest number of district borders as possible because crossing borders is usually a laborious task.

Imagine Circles Country as an infinite plane. You are given int[]s X, Y and R, where (X[i], Y[i]) are the coordinates of the i-th district’s center and R[i] is its radius. Qatam is currently at point (x1,y1) and he needs to get to point (x2,y2). Neither of these points lies on a district border. Return the minimal number of district borders he must cross to get to his destination.

#include <vector>
using namespace std;

class CirclesCountry {
    public:
        int leastBorders(vector <int> X, vector <int> Y, vector <int>R, int x1, int y1, int x2, int y2){
            int num = 0;

            for (int i = 0; i < X.size(); i++){
                if (inside(X[i], Y[i], x1, y1, R[i]) != (inside(X[i], Y[i], x2, y2, R[i])))
                    num++;
            }

            bool inside(int x1, int y1, int x2, int y2, int r){
                return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) <= r * r;
            }
        }
};

(x1 – x2) * (x1 – x2) + (y1 – y2) * (y1 – y2) <= r * r;が x1y1とx2y2で正しくなければ境界線が1つとなる。すなわち、insideでは片方が円の中にあり、片方が円の外に点があるかどうかを判定している。コーディングというより問題の理解力の方が求められるか...

SRM258 autoLoan

Auto dealerships frequently advertise tempting loan offers in order to make it easier for people to afford the “car of their dreams”. A typical sales tactic is to show you various cars, and then talk in terms of what your monthly payment would be, to say nothing of how much you are actually paying for the car, how much interest you pay, or how long you have to make payments.

A typical auto loan is calculated using a fixed interest rate, and is set up so that you make the same monthly payment for a set period of time in order to fully pay off the balance. The balance of your loan starts out as the sticker price of the car. Each month, the monthly interest is added to your balance, and the amount of your payment is subtracted from your balance. (The payment is subtracted after the interest is added.) The monthly interest rate is 1/12 of the yearly interest rate. Thus, if your annual percentage rate is 12%, then 1% of the remaining balance would be charged as interest each month.

You have been checking out some of the cars at your local dealership, TopAuto. An excited salesman has just approached you, shouting about how you can have the car you are looking at for a payment of only monthlyPayment for only loanTerm months! You are to return a double indicating the annual percentage rate of the loan, assuming that the initial balance of the loan is price.

#include <algorithm>
#include <cmath>
using namespace std;

class AutoLoan {
    double interestRate(double price, double monthlyPayment, int loanTerm){
        double balance;
        double high = 100, low = 0, mid = 0;

        while((1e-9 < high - low) && (1e-9 < (high -low)/high)){
            balance = price;
            mid = (high + low) / 2;

            for (int j=0; j<loanTerm; j++){
                balance *= mid / 1200 + 1;
                balance -= monthyPayment;
            }
            if (0 < balance) high = mid;
            else low = mid;
        }
        return mid;
    }
}

mid = (high + low) / 2; としてから、highとlowの差が限りなく小さくなるまでwhileで繰り返し処理を行う。
1e-2は0.01で、1e-9は0.000000001
“1e-n”という表現は覚えておいて損はなさそう

bitcoin.confの書き方

mainnet=1
txindex=1
server=1
rest=1
rpcuser="username"
rpcpassword="password"
rpcport=8332

testnet=1
txindex=1
server=1
rest=1
rpcuser="username"
rpcpassword="password"
rpcport=8332

mainnet or testnetの利用
indexを作成して全てのトランザクションIDを参照可能とする
json rpcサーバとしてコマンドを受け付ける
rest インターフェイスを有効にする
json rpcのためのユーザ名、パスワード、rpcポート
※JSON-RPCを利用することで、一般的なHTTPライブラリを使用してbitcoin coreと対話できる

testnet=3
server=1
rpcbind=localhost
rpcport=18332
rpcuser=hoge
rpcpassword=piyo

testnet=3とは現在のバージョン
regtestに接続する場合は regtest=1

SRM481 BatchSystem

#include <map>
#include <string>
#include <vector>
using namespace std;

class BachSystem {
    public:
        vector <int> schedule(vector<int> duration, vector <string> user){
            int N = duration.size();

            map<string, long long> jobTime;
            for(int n=0; n<N; n++) jobTime[user[n]] += duration[n];

            vector<bool> done(N);
            vector<int> ans;
            while(ans.size() < N) {
                string next;
                for(int n=0; n<N; n++){
                    if(!done[n] && (next.empty() || jobTime[user[n]] < jobTime[next]))
                        next = user[n];
                }

                for(int n=0; n<N; n++){
                    if(user[n] == next){
                        done[n] = true;
                        ans.push_back(n);
                    }
                }
            }
            return ans;
        }
}

empty()は空かどうか。
done[N]はNが1以降にならないとtrueにならない。

SRM232 StockHistory

You have recently been given a one-time bonus at work, along with a pay raise. In the interest of putting your new found money to good use, you have decided to invest in the stock market. To learn about recent market history, you have acquired historical data on several stocks you might be interested in purchasing.

For experiment’s sake, you want to evaluate the potential performance of your selected stocks. What you are wondering is how much money you could have made if, at the beginning, you had an initial investment of int initialInvestment dollars, and each month thereafter you had an additional int monthlyContribution dollars. Assume that you may buy any number of shares of stocks at the beginning of each month (including fractional numbers of shares), and that at the end of the timeframe (at the beginning of the last month) represented in the data, you sell all of your holdings. You may not sell stocks in the intermediate period. (See examples for clarification.)

You are given a String[], stockPrices, in which each element lists the prices of each stock at the beginning of a month. Each element of stockPrices is in the form “stock0 stock1 …” (quotes added for clarity), where each stocki is a positive integer with no leading zeroes. The first element of stockPrices gives the initial prices, the second element gives the prices at the beginning of the first month after you start investing, and so on.

You are to return an int indicating the maximum earnings (profit) you could make by the end of the timeframe. You should round your result to the nearest integer.

#include <cmath>
#include <string>
#include <vector>
using namespace std;

class StockHistory {
    public:
        int maximumEarnings(int initialInvestment, int monthlyContribution, vector <string> stockPrices){
            int money = initialInvestment;
            int month = stockPrices.size();
            int corp = 1:
            char *s = (char *)stockPrices[0].c_str();
            while(*s++) if(*s==' ') corp++;

            int prices[50][999];
            double max = 0; profit = 0;
            double proportion[50] = {0};
            bool buy[50] = {false};

            for(int i = 0; i < month; i++){
                string s = stockPrices[i];
                for(int j = 0; j < corp; j++){
                    int pos=s.find(" ");
                    if(pos == string::npos){
                        prices[i][j] = atoi(s.c_str());
                    } else {
                        prices[i][j] = atoi(s.substr(0, pos).c_str());
                        s = s.substr(pos+1, s.size());
                    }
                }
            }

            for(int i = month - 2; 0 <= i; i--){
                for(int j = 0; j < corp; j++){
                    double p = 1.0 * prices[month - 1][j] / prices[i][j] - 1;
                    if(0 < p && max < p) {
                        buy[i] = true;
                        max = p;
                        proportion[i] = p;
                    }
                    for(int i = 0; i < month; i++){
                        if(buy[i]){
                            profit += money * proportion[i];
                            money = 0;
                        }
                        money += monthlyContribution;
                    }
                    return (int)Math.round(profit);
                }
            }
        }
}