Skip to content

Commit

Permalink
segwit: Initial BIP142 implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
theuni committed Jan 20, 2016
1 parent d6e62d0 commit ede1b57
Show file tree
Hide file tree
Showing 12 changed files with 300 additions and 18 deletions.
86 changes: 71 additions & 15 deletions src/base58.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,9 @@ class CBitcoinAddressVisitor : public boost::static_visitor<bool>
CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}

bool operator()(const CKeyID& id) const { return addr->Set(id); }
bool operator()(const CWitKeyID160& id) const { return addr->Set(id); }
bool operator()(const CScriptID& id) const { return addr->Set(id); }
bool operator()(const CWitScriptID256& id) const { return addr->Set(id); }
bool operator()(const CNoDestination& no) const { return false; }
};

Expand All @@ -230,6 +232,28 @@ bool CBitcoinAddress::Set(const CScriptID& id)
return true;
}

bool CBitcoinAddress::Set(const CWitKeyID160& id)
{
unsigned char vch[22];
vch[0] = id.GetVersion();
vch[1] = 0;
const uint160& hash = id.GetHash();
memcpy(&vch[2], hash.begin(), 20);
SetData(Params().Base58Prefix(CChainParams::WIT_PUBKEY_ADDRESS), vch, sizeof(vch));
return IsWitness();
}

bool CBitcoinAddress::Set(const CWitScriptID256& id)
{
unsigned char vch[34];
vch[0] = id.GetVersion();
vch[1] = 0;
const uint256& hash = id.GetHash();
memcpy(&vch[2], hash.begin(), 32);
SetData(Params().Base58Prefix(CChainParams::WIT_SCRIPT_ADDRESS), vch, sizeof(vch));
return IsWitness();
}

bool CBitcoinAddress::Set(const CTxDestination& dest)
{
return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
Expand All @@ -242,39 +266,71 @@ bool CBitcoinAddress::IsValid() const

bool CBitcoinAddress::IsValid(const CChainParams& params) const
{
bool fCorrectSize = vchData.size() == 20;
bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
return fCorrectSize && fKnownVersion;
return IsWitness() || (vchData.size() == 20 &&
(vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS)));
}

bool CBitcoinAddress::IsWitness(const CChainParams& params) const
{
return (((vchVersion == params.Base58Prefix(CChainParams::WIT_PUBKEY_ADDRESS) && vchData.size() == 22) ||
(vchVersion == params.Base58Prefix(CChainParams::WIT_SCRIPT_ADDRESS) && vchData.size() == 34)) &&
vchData[0] >= 0 && vchData[0] <= 16 && vchData[1] == 0);
}

bool CBitcoinAddress::IsWitness() const
{
return IsWitness(Params());
}

CTxDestination CBitcoinAddress::Get() const
{
if (!IsValid())
return CNoDestination();
uint160 id;
memcpy(&id, &vchData[0], 20);
if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
return CKeyID(id);
else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
return CScriptID(id);
else
return CNoDestination();
if(IsWitness()) {
int nVersion = vchData[0];
if (vchData.size() == 22) {
uint160 id;
memcpy(id.begin(), &vchData[2], 20);
return CWitKeyID160(id, nVersion);
}
else if(vchData.size() == 34) {
uint256 id;
memcpy(id.begin(), &vchData[2], 32);
return CWitScriptID256(id, nVersion);
}
}
else if(vchData.size() == 20) {
uint160 id;
memcpy(&id, &vchData[0], 20);
if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
return CKeyID(id);
else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
return CScriptID(id);
}
return CNoDestination();
}

bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
{
if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
if (!IsValid())
return false;
uint160 id;
memcpy(&id, &vchData[0], 20);
if(vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) && vchData.size() == 20)
memcpy(&id, &vchData[0], 20);
else if(vchVersion == Params().Base58Prefix(CChainParams::WIT_PUBKEY_ADDRESS) && vchData.size() == 22)
memcpy(&id, &vchData[2], 20);
else
return false;

keyID = CKeyID(id);
return true;
}

bool CBitcoinAddress::IsScript() const
{
return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
return IsValid() && (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS) ||
vchVersion == Params().Base58Prefix(CChainParams::WIT_SCRIPT_ADDRESS));
}

void CBitcoinSecret::SetKey(const CKey& vchSecret)
Expand Down
5 changes: 4 additions & 1 deletion src/base58.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ class CBitcoinAddress : public CBase58Data {
bool Set(const CKeyID &id);
bool Set(const CScriptID &id);
bool Set(const CTxDestination &dest);
bool Set(const CWitKeyID160 &dest);
bool Set(const CWitScriptID256 &dest);
bool IsValid() const;
bool IsValid(const CChainParams &params) const;

CBitcoinAddress() {}
CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
Expand All @@ -117,6 +118,8 @@ class CBitcoinAddress : public CBase58Data {
CTxDestination Get() const;
bool GetKeyID(CKeyID &keyID) const;
bool IsScript() const;
bool IsWitness() const;
bool IsWitness(const CChainParams &params) const;
};

/**
Expand Down
6 changes: 6 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ class CMainParams : public CChainParams {
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container<std::vector<unsigned char> >();
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container<std::vector<unsigned char> >();
base58Prefixes[WIT_PUBKEY_ADDRESS] = std::vector<unsigned char>(1,6);
base58Prefixes[WIT_SCRIPT_ADDRESS] = std::vector<unsigned char>(1,10);

vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));

Expand Down Expand Up @@ -190,6 +192,8 @@ class CTestNetParams : public CChainParams {
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container<std::vector<unsigned char> >();
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >();
base58Prefixes[WIT_PUBKEY_ADDRESS] = std::vector<unsigned char>(1,3);
base58Prefixes[WIT_SCRIPT_ADDRESS] = std::vector<unsigned char>(1,40);

vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));

Expand Down Expand Up @@ -250,6 +254,8 @@ class CSegNetParams : public CChainParams {
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,158);
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x05)(0x35)(0x87)(0xCF).convert_to_container<std::vector<unsigned char> >();
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x05)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >();
base58Prefixes[WIT_PUBKEY_ADDRESS] = std::vector<unsigned char>(1,3);
base58Prefixes[WIT_SCRIPT_ADDRESS] = std::vector<unsigned char>(1,40);

vFixedSeeds.clear();

Expand Down
2 changes: 2 additions & 0 deletions src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class CChainParams
SECRET_KEY,
EXT_PUBLIC_KEY,
EXT_SECRET_KEY,
WIT_PUBKEY_ADDRESS,
WIT_SCRIPT_ADDRESS,

MAX_BASE58_TYPES
};
Expand Down
20 changes: 20 additions & 0 deletions src/pubkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ class CKeyID : public uint160
CKeyID(const uint160& in) : uint160(in) {}
};

class CWitKeyID160
{
public:
CWitKeyID160() : nVersion(0) {}
CWitKeyID160(const uint160& in, int nVersionIn) : hash(in), nVersion(nVersionIn) {}
bool operator<(const CWitKeyID160& in) const
{
return in.nVersion < nVersion || in.hash < hash;
}
bool operator==(const CWitKeyID160& in) const
{
return in.nVersion == nVersion && in.hash == hash;
}
const uint160& GetHash() const { return hash; }
int GetVersion() const { return nVersion; }
private:
uint160 hash;
int nVersion;
};

typedef uint256 ChainCode;

/** An encapsulated public key. */
Expand Down
40 changes: 40 additions & 0 deletions src/rpcmisc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,46 @@ class DescribeAddressVisitor : public boost::static_visitor<UniValue>
}
return obj;
}

UniValue operator()(const CWitKeyID160 &keyID) const {
UniValue obj(UniValue::VOBJ);
CPubKey vchPubKey;
obj.push_back(Pair("isscript", false));
if (pwalletMain && pwalletMain->GetPubKey(keyID.GetHash(), vchPubKey)) {
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
}
return obj;
}

UniValue operator()(const CWitScriptID256 &scriptID) const {
UniValue obj(UniValue::VOBJ);

const uint256& hash256 = scriptID.GetHash();
uint160 hash;
CRIPEMD160().Write(hash256.begin(), hash256.size()).Finalize(hash.begin());
CScriptID id = CScriptID(hash);

CScript subscript;
obj.push_back(Pair("isscript", true));
if (pwalletMain && pwalletMain->GetCScript(id, subscript)) {
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
ExtractDestinations(subscript, whichType, addresses, nRequired);
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
UniValue a(UniValue::VARR);
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
obj.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
obj.push_back(Pair("sigsrequired", nRequired));
}

return obj;
}

};
#endif

Expand Down
22 changes: 22 additions & 0 deletions src/script/standard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;

CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {}
CWitScriptID256::CWitScriptID256(const CScript& in, int nVersionIn) : hash(Hash(in.begin(), in.end())), nVersion(nVersionIn) {}

const char* GetTxnOutputType(txnouttype t)
{
Expand Down Expand Up @@ -230,6 +231,16 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
addressRet = CScriptID(uint160(vSolutions[0]));
return true;
}
else if (whichType == TX_WITNESS_V0_KEYHASH)
{
addressRet = CWitKeyID160(uint160(vSolutions[0]), 0);
return true;
}
else if (whichType == TX_WITNESS_V0_SCRIPTHASH)
{
addressRet = CWitScriptID256(uint256(vSolutions[0]), 0);
return true;
}
// Multisig txns have more than one address...
return false;
}
Expand Down Expand Up @@ -299,6 +310,17 @@ class CScriptVisitor : public boost::static_visitor<bool>
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
return true;
}

bool operator()(const CWitKeyID160 &keyID) const {
script->clear();
*script << keyID.GetVersion() << ToByteVector(keyID.GetHash());
return true;
}
bool operator()(const CWitScriptID256 &scriptID) const {
script->clear();
*script << scriptID.GetVersion() << ToByteVector(scriptID.GetHash());
return true;
}
};
}

Expand Down
24 changes: 23 additions & 1 deletion src/script/standard.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ static const bool DEFAULT_ACCEPT_DATACARRIER = true;

class CKeyID;
class CScript;
class CWitKeyID160;

/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
class CScriptID : public uint160
Expand All @@ -27,6 +28,27 @@ class CScriptID : public uint160
CScriptID(const uint160& in) : uint160(in) {}
};

class CWitScriptID256
{
public:
CWitScriptID256() : nVersion(0) {}
CWitScriptID256(const CScript& in, int nVersionIn);
CWitScriptID256(const uint256& in, int nVersionIn) : hash(in), nVersion(nVersionIn) {}
bool operator<(const CWitScriptID256& in) const
{
return in.nVersion < nVersion || in.hash < hash;
}
bool operator==(const CWitScriptID256& in) const
{
return in.nVersion == nVersion && in.hash == hash;
}
const uint256& GetHash() const { return hash; }
int GetVersion() const { return nVersion; }
private:
uint256 hash;
int nVersion;
};

static const unsigned int MAX_OP_RETURN_RELAY = 83; //! bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)
extern bool fAcceptDatacarrier;
extern unsigned nMaxDatacarrierBytes;
Expand Down Expand Up @@ -68,7 +90,7 @@ class CNoDestination {
* * CScriptID: TX_SCRIPTHASH destination
* A CTxDestination is the internal data type encoded in a CBitcoinAddress
*/
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
typedef boost::variant<CNoDestination, CKeyID, CScriptID, CWitKeyID160, CWitScriptID256> CTxDestination;

const char* GetTxnOutputType(txnouttype t);

Expand Down
Loading

0 comments on commit ede1b57

Please sign in to comment.