どのようにしてエーテル坊(アンドロイド)財布シリーズを開発します1-補助語を通じてアカウントを作成します


本文は深入浅出区ブロックチェーンコミュニティの原文リンクに先発します:以太坊(アンドロイド)財布シリーズ1-助記詞を通じてアカウントを作成します原文はすでに更新して、読者に原文に行って読んでください
先週、財布をオープンしました.よく反映されています.一週間もしないうちに100スターに着きました.次はいくつかのシリーズの文章で以太坊財布を開発する核心的な要点を書き、コードの解読にもなります.
前に書く
財布はAndroidアンドロイドプラットフォームを使用して作成され、オリジナルコードJava言語を使用して作成され、Java 1.8バージョンに基づいており、Java 1.8のいくつかの新しい言語特性、例えばLambda式なども使用されています.また、ReactiveX/RxAndroidレスポンスプログラミングの使用も多い.
このシリーズでは、以太坊財布の口座番号や取引などの論理を紹介することに重点を置き、読者がAndroid開発などの知識を知っていると仮定する場合がありますが、これらの内容は文章の重点ではないので、あまり紹介しないので、お許しください.
ウォレットに含まれる機能
通常、財布には次の機能が含まれます.
  • [x]は、助記語、Keystoreファイル、秘密鍵を生成することによって財布アカウントを作成することをサポートする.
  • [x]は、財布アカウントの助記語、秘密鍵、Keystoreファイルのエクスポートをサポートします.
  • [x]は複数の財布口座管理
  • をサポートする
  • [x]口座残高照会および振替機能(QRコードスキャンサポート).
  • [x]はERC 20コイン(残高表示、振替、コイン価格表示)
  • をサポートする.
  • [x]は、フランスドル(ドルと人民元)で通貨価格をリアルタイムで表示することをサポートします.
  • [x]履歴取引リスト
  • を表示
    アカウント予備知識の作成
    まず、最初の機能を紹介します.アシストワード、Keystoreファイル、秘密鍵を生成して財布アカウントを作成します.このシリーズでは、財布とは階層確定財布のことで、以前ブログで階層財布について詳しく紹介した記事がありましたが、まだ詳しくは読めません.本明細書の完全性を維持するために、ここでは、太坊およびビットコインのアドレスがランダムに生成された秘密鍵が楕円曲線などのアルゴリズムによって一方向に押し倒され、BIP 32およびBIP 44は秘密鍵の管理を容易にするために提案された階層化押し倒されたスキームであり、BIP 39定義助記語は階層化種子のバックアップをより便利にする.一方、KeyStoreファイルは、太坊が秘密鍵を保存していることを復号するための方法で、アカウントKeystoreファイルのインポートとエクスポートについては、次の記事を参照してください.
    次の図のようなインタフェースで実装されています.
    これは財布アカウントをインポートするスクリーンショット(インポートと作成、実は原理は同じ)で、インタフェースはImTokenを模倣していますが、UI部分の作成はここでは紹介しません.
    Web3j & bitcoinj
    アカウント作成機能を完了するには、Web 3 jとbitcoinjの2つのライブラリを使用する必要があります.
    Web 3はイーサー坊と通信するパッケージライブラリであり、Web 3 jはJavaバージョンの実装であり、例えば取引の開始とスマート契約のインタラクションであり、下図はその役割をよく示している.
    しかし,本稿の機能は,主にweb 3 jにおける楕円曲線暗号化およびKeyStoreファイルの生成と復号化を用いた.
    bitcoinjの機能はweb 3と類似しており、ビットコインプロトコルのJava実装であり、BIP 32、BIP 44、BIP 39関連プロトコルを実現している.
    AndroidはGradleを使用して構築され、app/build.gradleファイルに直接追加されます.
    implementation 'org.web3j:core:4.1.0-android'
    implementation 'org.bitcoinj:bitcoinj-core:0.14.7'

    ヒント:実際に発生した問題は、bitcoinjにcom.lambdaworks:scrypt暗号化ライブラリが導入されているため、lib/x86_64/darwin/libscrypt.dylibファイルが含まれているため、Android App Bundleのコンパイル中にエラーが発生し(一部の機種ではインストールできないようです)、build.gradleに文を追加して、このファイルをパッケージ化時に排除することです.packagingOptions {
    exclude 'lib/x86_64/darwin/libscrypt.dylib'

    }
    アカウント実装の作成
    助数詞でよく見かける財布のアカウント
    これは現在の財布クライアントで、最も一般的なユーザーの一般的なアカウントの方法で、ここにはいくつかのコアステップが含まれています.
  • 乱数シードを生成する.
  • ランダム数の種子によって助記語が得られる.
  • シード+パス派生により秘密鍵を生成する.
  • KeyStoreを使用して秘密鍵を保存する.
  • 秘密鍵はアカウントアドレスを押し出す.

  • 階層財布をもう一度読んで、なぜそうしたのかを理解することができます.
    上記の点を理解すると、コードは分かりやすくなります.コードはコードライブラリのapp/src/pro/upchain/wallet/utils/ETHWalletUtils.javaにあり、キーコードロジックは以下の通りです.
        //           
        public static ETHWallet generateMnemonic(String walletName, String pwd) {
            String[] pathArray = "m/44'/60'/0'/0/0".split("/");
    
            long creationTimeSeconds = System.currentTimeMillis() / 1000;
    
            SecureRandom secureRandom = SecureRandomUtils.secureRandom();
            DeterministicSeed ds = new DeterministicSeed(secureRandom, 128, "", creationTimeSeconds);
    
            return generateWalletByMnemonic(walletName, ds, pathArray, pwd);
        }
    
        /**
         * @param walletName     
         * @param ds                
         * @param pathArray       
         * @param pwd          
         * @return
         */
        @Nullable
        public static ETHWallet generateWalletByMnemonic(String walletName, DeterministicSeed ds,
                                                         String[] pathArray, String pwd) {
            //  
            byte[] seedBytes = ds.getSeedBytes();
            //   
            List mnemonic = ds.getMnemonicCode();
    
            if (seedBytes == null)
                return null;
    
            //      key
            DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(seedBytes);
            for (int i = 1; i < pathArray.length; i++) {
                ChildNumber childNumber;
                if (pathArray[i].endsWith("'")) {
                    int number = Integer.parseInt(pathArray[i].substring(0,
                            pathArray[i].length() - 1));
                    childNumber = new ChildNumber(number, true);
                } else {
                    int number = Integer.parseInt(pathArray[i]);
                    childNumber = new ChildNumber(number, false);
                }
                dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber);
            }
    
            ECKeyPair keyPair = ECKeyPair.create(dkKey.getPrivKeyBytes());
            ETHWallet ethWallet = generateWallet(walletName, pwd, keyPair);
            if (ethWallet != null) {
                ethWallet.setMnemonic(convertMnemonicList(mnemonic));
            }
            return ethWallet;
        }
    
            @Nullable
        private static ETHWallet generateWallet(String walletName, String pwd, ECKeyPair ecKeyPair) {
            WalletFile keyStoreFile;
            try {
                keyStoreFile = Wallet.create(pwd, ecKeyPair, 1024, 1); // WalletUtils. .generateNewWalletFile();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
    
            BigInteger publicKey = ecKeyPair.getPublicKey();
            String s = publicKey.toString();
    
            String wallet_dir = AppFilePath.Wallet_DIR;
    
            String keystorePath = "keystore_" + walletName + ".json";
            File destination = new File(wallet_dir, "keystore_" + walletName + ".json");
    
            //          ,       
            if (!createParentDir(destination)) {
                return null;
            }
            try {
                objectMapper.writeValue(destination, keyStoreFile);
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
    
            ETHWallet ethWallet = new ETHWallet();
            ethWallet.setName(walletName);
            ethWallet.setAddress(Keys.toChecksumAddress(keyStoreFile.getAddress()));
            ethWallet.setKeystorePath(destination.getAbsolutePath());
            ethWallet.setPassword(Md5Utils.md5(pwd));
            return ethWallet;
        }
    

    上記のコードでは、generateMnemonic()はエントリ関数であり、最終的にはETHWalletカスタムの財布エンティティクラスが返され、1つのインスタンスは1つの財布に対応し、ETHWalletは財布関連の属性を保存しており、後で詳しく説明し、財布アカウントの保存と複数の財布アカウントの管理をシーケンス化すればよい.
    いくつかの注意事項
    アシストワードや秘密鍵の保存については、特に注意しなければならない点がいくつかあります.そうしないと、他の財布と互換性がないか、秘密鍵が漏れる可能性があります.
    この部分は購読者の福祉として、私の小さなコラムに発表して、まだ値上げしていないうちに、急いで購読しましょう.価値があります.
    リファレンスドキュメント
  • web 3 j APIドキュメント
  • bitcoinj紹介およびドキュメント
  • 知識星に参加し、優秀なブロックチェーン業者と一緒に勉強します.ブロックチェーンを深く浅くする-システムはブロックチェーンを学習し、最高のブロックチェーン技術ブログを構築する.