txscript: Add API to parse atomic swap contracts.

This commit is contained in:
Josh Rickmar 2017-09-20 13:44:35 -04:00 committed by Dave Collins
parent 91e5ba1a80
commit 4803a8291c

View file

@ -623,3 +623,70 @@ func ExtractPkScriptAddrs(pkScript []byte, chainParams *chaincfg.Params) (Script
return scriptClass, addrs, requiredSigs, nil
}
// AtomicSwapDataPushes houses the data pushes found in atomic swap contracts.
type AtomicSwapDataPushes struct {
RecipientHash160 [20]byte
RefundHash160 [20]byte
SecretHash [20]byte
LockTime int64
}
// ExtractAtomicSwapDataPushes returns the data pushes from an atomic swap
// contract. If the script is not an atomic swap contract,
// ExtractAtomicSwapDataPushes returns (nil, nil). Non-nil errors are returned
// for unparsable scripts.
//
// NOTE: Atomic swaps are not considered standard script types by the dcrd
// mempool policy and should be used with P2SH. The atomic swap format is also
// expected to change to use a more secure hash function in the future.
//
// This function is only defined in the txscript package due to API limitations
// which prevent callers using txscript to parse nonstandard scripts.
func ExtractAtomicSwapDataPushes(pkScript []byte) (*AtomicSwapDataPushes, error) {
pops, err := parseScript(pkScript)
if err != nil {
return nil, err
}
if len(pops) != 17 {
return nil, nil
}
isAtomicSwap := pops[0].opcode.value == OP_IF &&
pops[1].opcode.value == OP_RIPEMD160 &&
pops[2].opcode.value == OP_DATA_20 &&
pops[3].opcode.value == OP_EQUALVERIFY &&
pops[4].opcode.value == OP_DUP &&
pops[5].opcode.value == OP_HASH160 &&
pops[6].opcode.value == OP_DATA_20 &&
pops[7].opcode.value == OP_ELSE &&
canonicalPush(pops[8]) &&
pops[9].opcode.value == OP_CHECKLOCKTIMEVERIFY &&
pops[10].opcode.value == OP_DROP &&
pops[11].opcode.value == OP_DUP &&
pops[12].opcode.value == OP_HASH160 &&
pops[13].opcode.value == OP_DATA_20 &&
pops[14].opcode.value == OP_ENDIF &&
pops[15].opcode.value == OP_EQUALVERIFY &&
pops[16].opcode.value == OP_CHECKSIG
if !isAtomicSwap {
return nil, nil
}
pushes := new(AtomicSwapDataPushes)
copy(pushes.SecretHash[:], pops[2].data)
copy(pushes.RecipientHash160[:], pops[6].data)
copy(pushes.RefundHash160[:], pops[13].data)
if pops[8].data != nil {
locktime, err := makeScriptNum(pops[8].data, true, 5)
if err != nil {
return nil, nil
}
pushes.LockTime = int64(locktime)
} else if op := pops[8].opcode; isSmallInt(op) {
pushes.LockTime = int64(asSmallInt(op))
} else {
return nil, nil
}
return pushes, nil
}