@Override public List<Protos.Key> serializeToProtobuf() { lock.lock(); try { // Most of the serialization work is delegated to the basic key chain, which will serialize // the bulk of the // data (handling encryption along the way), and letting us patch it up with the extra data we // care about. LinkedList<Protos.Key> entries = newLinkedList(); if (seed != null) { Protos.Key.Builder mnemonicEntry = BasicKeyChain.serializeEncryptableItem(seed); mnemonicEntry.setType(Protos.Key.Type.DETERMINISTIC_MNEMONIC); entries.add(mnemonicEntry.build()); } Map<ECKey, Protos.Key.Builder> keys = basicKeyChain.serializeToEditableProtobufs(); for (Map.Entry<ECKey, Protos.Key.Builder> entry : keys.entrySet()) { DeterministicKey key = (DeterministicKey) entry.getKey(); Protos.Key.Builder proto = entry.getValue(); proto.setType(Protos.Key.Type.DETERMINISTIC_KEY); final Protos.DeterministicKey.Builder detKey = proto.getDeterministicKeyBuilder(); detKey.setChainCode(ByteString.copyFrom(key.getChainCode())); for (ChildNumber num : key.getPath()) detKey.addPath(num.i()); if (key.equals(externalKey)) { detKey.setIssuedSubkeys(issuedExternalKeys); detKey.setLookaheadSize(lookaheadSize); } else if (key.equals(internalKey)) { detKey.setIssuedSubkeys(issuedInternalKeys); detKey.setLookaheadSize(lookaheadSize); } // Flag the very first key of following keychain. if (entries.isEmpty() && isFollowing()) { detKey.setIsFollowing(true); } if (key.getParent() != null) { // HD keys inherit the timestamp of their parent if they have one, so no need to serialize // it. proto.clearCreationTimestamp(); } entries.add(proto.build()); } return entries; } finally { lock.unlock(); } }
/** * Converts the given wallet to the object representation of the protocol buffers. This can be * modified, or additional data fields set, before serialization takes place. */ public Protos.Wallet walletToProto(Wallet wallet) { Protos.Wallet.Builder walletBuilder = Protos.Wallet.newBuilder(); walletBuilder.setNetworkIdentifier(wallet.getNetworkParameters().getId()); if (wallet.getDescription() != null) { walletBuilder.setDescription(wallet.getDescription()); } for (WalletTransaction wtx : wallet.getWalletTransactions()) { Protos.Transaction txProto = makeTxProto(wtx); walletBuilder.addTransaction(txProto); } for (ECKey key : wallet.getKeys()) { Protos.Key.Builder keyBuilder = Protos.Key.newBuilder() .setCreationTimestamp(key.getCreationTimeSeconds() * 1000) // .setLabel() TODO .setType(Protos.Key.Type.ORIGINAL); if (key.getPrivKeyBytes() != null) keyBuilder.setPrivateKey(ByteString.copyFrom(key.getPrivKeyBytes())); EncryptedPrivateKey encryptedPrivateKey = key.getEncryptedPrivateKey(); if (encryptedPrivateKey != null) { // Key is encrypted. Protos.EncryptedPrivateKey.Builder encryptedKeyBuilder = Protos.EncryptedPrivateKey.newBuilder() .setEncryptedPrivateKey( ByteString.copyFrom(encryptedPrivateKey.getEncryptedBytes())) .setInitialisationVector( ByteString.copyFrom(encryptedPrivateKey.getInitialisationVector())); if (key.getKeyCrypter() == null) { throw new IllegalStateException( "The encrypted key " + key.toString() + " has no KeyCrypter."); } else { // If it is a Scrypt + AES encrypted key, set the persisted key type. if (key.getKeyCrypter().getUnderstoodEncryptionType() == Protos.Wallet.EncryptionType.ENCRYPTED_SCRYPT_AES) { keyBuilder.setType(Protos.Key.Type.ENCRYPTED_SCRYPT_AES); } else { throw new IllegalArgumentException( "The key " + key.toString() + " is encrypted with a KeyCrypter of type " + key.getKeyCrypter().getUnderstoodEncryptionType() + ". This WalletProtobufSerialiser does not understand that type of encryption."); } } keyBuilder.setEncryptedPrivateKey(encryptedKeyBuilder); } // We serialize the public key even if the private key is present for speed reasons: we don't // want to do // lots of slow EC math to load the wallet, we prefer to store the redundant data instead. It // matters more // on mobile platforms. keyBuilder.setPublicKey(ByteString.copyFrom(key.getPubKey())); walletBuilder.addKey(keyBuilder); } // Populate the lastSeenBlockHash field. Sha256Hash lastSeenBlockHash = wallet.getLastBlockSeenHash(); if (lastSeenBlockHash != null) { walletBuilder.setLastSeenBlockHash(hashToByteString(lastSeenBlockHash)); walletBuilder.setLastSeenBlockHeight(wallet.getLastBlockSeenHeight()); } // Populate the scrypt parameters. KeyCrypter keyCrypter = wallet.getKeyCrypter(); if (keyCrypter == null) { // The wallet is unencrypted. walletBuilder.setEncryptionType(EncryptionType.UNENCRYPTED); } else { // The wallet is encrypted. walletBuilder.setEncryptionType(keyCrypter.getUnderstoodEncryptionType()); if (keyCrypter instanceof KeyCrypterScrypt) { KeyCrypterScrypt keyCrypterScrypt = (KeyCrypterScrypt) keyCrypter; walletBuilder.setEncryptionParameters(keyCrypterScrypt.getScryptParameters()); } else { // Some other form of encryption has been specified that we do not know how to persist. throw new RuntimeException( "The wallet has encryption of type '" + keyCrypter.getUnderstoodEncryptionType() + "' but this WalletProtobufSerializer does not know how to persist this."); } } populateExtensions(wallet, walletBuilder); // Populate the wallet version. walletBuilder.setVersion(wallet.getVersion()); return walletBuilder.build(); }