mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-13 02:35:52 +00:00
This implements micropayment payment channels in several parts: * Adds PaymentChannel[Server|Client]State state machines which handle initialization of the payment channel, keep track of basic in-memory state, and check data received from the other side, based on Mike Hearn's initial implementation. * StoredPaymentChannel[Client|Server]States manage channel timeout+broadcasting of relevant transactions at that time, keeping track of state objects which allow for channel resume, and are saved/loaded as a WalletExtension. * Adds PaymentChannel[Client|Server] which manage a connection by getting new protobufs, generating protobufs for the other side, properly stepping the associated State object and ensuring the StoredStates object is properly used to save state in the wallet. * Adds PaymentChannel[ClientConnection|ServerListener] which create TCP sockets to each other and use PaymentChannel[Client|Server] objects to create/use payment channels. The algorithm implemented is the one described at https://en.bitcoin.it/wiki/Contracts#Example_7:_Rapidly-adjusted_.28micro.29payments_to_a_pre-determined_party with a slight tweak to use looser SIGHASH flags so that the Wallet.completeTx code can work its magic by adding more inputs if it saves on fees. Thanks to Mike Hearn for the initial state machine implementations and all his contracts work and Jeremy Spilman for suggesting the protocol modification that works with non-standard nLockTime Transactions.
211 lines
11 KiB
Protocol Buffer
211 lines
11 KiB
Protocol Buffer
/** Copyright 2013 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* Authors: Mike Hearn, Matt Corallo
|
|
*/
|
|
|
|
/* Notes:
|
|
* - Endianness: All byte arrays that represent numbers (such as hashes and private keys) are Big Endian
|
|
* - To regenerate after editing, run mvn clean package -DupdateProtobuf
|
|
*/
|
|
|
|
package paymentchannels;
|
|
|
|
option java_package = "org.bitcoin.paymentchannel";
|
|
option java_outer_classname = "Protos";
|
|
|
|
|
|
// The connection should be a standard TLS connection and all messages sent over this socket are
|
|
// serialized TwoWayChannelMessages prefixed with 2-byte size in big-endian (smaller than or
|
|
// equal to 32767 bytes in size)
|
|
message TwoWayChannelMessage {
|
|
enum MessageType {
|
|
CLIENT_VERSION = 1;
|
|
SERVER_VERSION = 2;
|
|
INITIATE = 3;
|
|
PROVIDE_REFUND = 4;
|
|
RETURN_REFUND = 5;
|
|
PROVIDE_CONTRACT = 6;
|
|
// Note that there are no optional fields set for CHANNEL_OPEN, it is sent from the
|
|
// secondary to the primary to indicate that the provided contract was received,
|
|
// verified, and broadcast successfully and the primary can now provide UPDATE messages
|
|
// at will to begin paying secondary. If the channel is interrupted after the
|
|
// CHANNEL_OPEN message (ie closed without an explicit CLOSE or ERROR) the primary may
|
|
// reopen the channel by setting the contract transaction hash in its CLIENT_VERSION
|
|
// message.
|
|
CHANNEL_OPEN = 7;
|
|
UPDATE_PAYMENT = 8;
|
|
// Note that there are no optional fields set for CLOSE, it is sent by either party to
|
|
// indicate that the channel is now closed and no further updates can happen. After this,
|
|
// the secondary takes the most recent signature it received in an UPDATE_PAYMENT and
|
|
// uses it to create a valid transaction, which it then broadcasts on the network.
|
|
CLOSE = 9;
|
|
|
|
// Used to indicate an error condition.
|
|
// Both parties should make an effort to send either an ERROR or a CLOSE immediately
|
|
// before closing the socket (unless they just received an ERROR or a CLOSE)
|
|
ERROR = 10;
|
|
};
|
|
|
|
// This is required so if a new message type is added in future, old software aborts trying
|
|
// to read the message as early as possible. If the message doesn't parse, the socket should
|
|
// be closed.
|
|
required MessageType type = 1;
|
|
|
|
// Now one optional field for each message. Only the field specified by type should be read.
|
|
optional ClientVersion client_version = 2;
|
|
optional ServerVersion server_version = 3;
|
|
optional Initiate initiate = 4;
|
|
optional ProvideRefund provide_refund = 5;
|
|
optional ReturnRefund return_refund = 6;
|
|
optional ProvideContract provide_contract = 7;
|
|
optional UpdatePayment update_payment = 8;
|
|
|
|
optional Error error = 10;
|
|
}
|
|
|
|
// Sent by primary to secondary on opening the connection. If anything is received before this is
|
|
// sent, the socket is closed.
|
|
message ClientVersion {
|
|
required int32 major = 1;
|
|
optional int32 minor = 2 [default = 0];
|
|
|
|
// The hash of the multisig contract of a previous channel. This indicates that the primary
|
|
// wishes to reopen the given channel. If the server is willing to reopen it, it simply
|
|
// responds with a SERVER_VERSION and then immediately sends a CHANNEL_OPEN, it otherwise
|
|
// follows SERVER_VERSION with an Initiate representing a new channel
|
|
optional bytes previous_channel_contract_hash = 3;
|
|
}
|
|
|
|
// Send by secondary to primary upon receiving the ClientVersion message. If it is willing to
|
|
// speak the given major version, it sends back the same major version and the minor version it
|
|
// speaks. If it is not, it may send back a lower major version representing the highest version
|
|
// it is willing to speak, or sends a NO_ACCEPTABLE_VERSION Error. If the secondary sends back a
|
|
// lower major version, the secondary should either expect to continue with that version, or
|
|
// should immediately close the connection with a NO_ACCEPTABLE_VERSION Error. Backwards
|
|
// incompatible changes to the protocol bump the major version. Extensions bump the minor version
|
|
message ServerVersion {
|
|
required int32 major = 1;
|
|
optional int32 minor = 2 [default = 0];
|
|
}
|
|
|
|
// Sent from secondary to primary once version nego is done.
|
|
message Initiate {
|
|
// This must be a raw pubkey in regular ECDSA form. Both compressed and non-compressed forms
|
|
// are accepted. It is used only in the creation of the multisig contract, as outputs are
|
|
// created entirely by the secondary
|
|
required bytes multisig_key = 1;
|
|
|
|
// Once a channel is exhausted a new one must be set up. So secondary indicates the minimum
|
|
// size it's willing to accept here. This can be lower to trade off resources against
|
|
// security but shouldn't be so low the transactions get rejected by the network as spam.
|
|
// Zero isn't a sensible value to have here, so we make the field required.
|
|
required uint64 min_accepted_channel_size = 2;
|
|
|
|
// Rough UNIX time for when the channel expires. This is determined by the block header
|
|
// timestamps which can be very inaccurate when miners use the obsolete RollNTime hack.
|
|
// Channels could also be specified in terms of block heights but then how do you know the
|
|
// current chain height if you don't have internet access? Trust secondary? Probably opens up
|
|
// attack vectors. We can assume primary has an independent clock, however. If primary
|
|
// considers this value too far off (eg more than a day), it may send an ERROR and close the
|
|
// channel.
|
|
required uint64 expire_time_secs = 3;
|
|
}
|
|
|
|
// Sent from primary to secondary after Initiate to begin the refund transaction signing.
|
|
message ProvideRefund {
|
|
// This must be a raw pubkey in regular ECDSA form. Both compressed and non-compressed forms
|
|
// are accepted. It is only used in the creation of the multisig contract.
|
|
required bytes multisig_key = 1;
|
|
|
|
// The serialized bytes of the return transaction in Satoshi format.
|
|
// * It must have exactly one input which spends the multisig output (see ProvideContract for
|
|
// details of exactly what that output must look like). This output must have a sequence
|
|
// number of 0.
|
|
// * It must have the lock time set to a time after the min_time_window_secs (from the
|
|
// Initiate message).
|
|
// * It must have exactly one output which goes back to the primary. This output's
|
|
// scriptPubKey will be reused to create payment transactions.
|
|
required bytes tx = 2;
|
|
}
|
|
|
|
// Sent from secondary to primary after it has done initial verification of the refund
|
|
// transaction. Contains the primary's signature which is required to spend the multisig contract
|
|
// to the refund transaction. Must be signed using SIGHASH_NONE|SIGHASH_ANYONECANPAY (and include
|
|
// the postfix type byte) to allow the client to add any outputs/inputs it wants as long as the
|
|
// input's sequence and transaction's nLockTime remain set.
|
|
message ReturnRefund {
|
|
required bytes signature = 1;
|
|
}
|
|
|
|
// Sent from the primary to the secondary to complete initialization.
|
|
message ProvideContract {
|
|
// The serialized bytes of the transaction in Satoshi format.
|
|
// * It must be signed and completely valid and ready for broadcast (ie it includes the
|
|
// necessary fees) TODO: tell the client how much fee it needs
|
|
// * Its first output must be a 2-of-2 multisig output with the first pubkey being the
|
|
// primary's and the second being the secondary's (ie the script must be exactly "OP_2
|
|
// ProvideRefund.multisig_key Initiate.multisig_key OP_2 OP_CHECKMULTISIG")
|
|
required bytes tx = 1;
|
|
}
|
|
|
|
// This message can only be used by the primary after it has received a CHANNEL_OPEN message. It
|
|
// creates a new payment transaction. Note that we don't resubmit the entire TX, this is to avoid
|
|
// (re)parsing bugs and overhead. The payment transaction is created by the primary by:
|
|
// * Adding an input which spends the multisig contract
|
|
// * Setting this input's scriptSig to the given signature and a new signature created by the
|
|
// primary (the primary should ensure the signature provided correctly spends the multisig
|
|
// contract)
|
|
// * Adding an output who's scriptPubKey is the same as the refund output (the only output) in
|
|
// the refund transaction
|
|
// * Setting this output's value to client_change_value (which must be lower than the most recent
|
|
// client_change_value and lower than the multisig contract's output value)
|
|
// * Adding any number of additional outputs as desired (leaving sufficient fee, if necessary)
|
|
// * Adding any number of additional inputs as desired (eg to add more fee)
|
|
message UpdatePayment {
|
|
// The value which is sent back to the primary. The rest of the multisig output is left for
|
|
// the secondary to do with as they wish.
|
|
required uint64 client_change_value = 1;
|
|
// A SIGHASH_SINGLE|SIGHASH_ANYONECANPAY signature (including the postfix type byte) which
|
|
// spends the primary's part of the multisig contract's output. This signature only covers
|
|
// the primary's refund output and thus the secondary is free to do what they wish with their
|
|
// part of the multisig output.
|
|
required bytes signature = 2;
|
|
}
|
|
|
|
|
|
// An Error can be sent by either party at any time
|
|
// Both parties should make an effort to send either an ERROR or a CLOSE immediately before
|
|
// closing the socket (unless they just received an ERROR or a CLOSE)
|
|
message Error {
|
|
enum ErrorCode {
|
|
TIMEOUT = 1; // Protocol timeout occurred (one party hung).
|
|
SYNTAX_ERROR = 2; // Generic error indicating some message was not properly
|
|
// formatted or was out of order.
|
|
NO_ACCEPTABLE_VERSION = 3; // We don't speak the version the other side asked for.
|
|
BAD_TRANSACTION = 4; // A provided transaction was not in the proper structure
|
|
// (wrong inputs/outputs, sequence, lock time, signature,
|
|
// etc)
|
|
TIME_WINDOW_TOO_LARGE = 5; // The expire time specified by the secondary was too large
|
|
// for the primary
|
|
CHANNEL_VALUE_TOO_LARGE = 6; // The minimum channel value specified by the secondary was
|
|
// too large for the primary
|
|
|
|
OTHER = 7;
|
|
};
|
|
optional ErrorCode code = 1 [default=OTHER];
|
|
optional string explanation = 2; // NOT SAFE FOR HTML WITHOUT ESCAPING
|
|
} |