Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions txscript/stdaddr/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,15 @@ type StakeAddress interface {
// RewardCommitmentScript returns the script version associated with the
// address along with a script that commits the original funds locked to
// purchase a ticket plus the reward to the address along with limits to
// impose on any fees.
RewardCommitmentScript(amount int64, limits uint16) (uint16, []byte)
// impose on any fees (in atoms).
//
// Note that fee limits are encoded in the commitment script in terms of the
// closest base 2 exponent that results in a limit that is >= the provided
// limit. In other words, the limits are rounded up to the next power of 2
// when they are not already an exact power of 2. For example, a revocation
// limit of 2^23 + 1 will result in allowing a revocation fee of up to 2^24
// atoms.
RewardCommitmentScript(amount, voteFeeLimit, revocationFeeLimit int64) (uint16, []byte)

// StakeChangeScript returns the script version associated with the address
// along with a script to pay change to the address. It is only valid when
Expand Down
21 changes: 11 additions & 10 deletions txscript/stdaddr/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ func TestAddresses(t *testing.T) {
payScript string // hex-encoded expected payment script
voteScript string // hex-encoded expected voting rights script
rewardAmount int64 // reward commitment amount
feeLimits uint16 // reward fee limits commitment
voteFeeLimit int64 // reward commitment vote fee limit
revFeeLimit int64 // reward commitment revoke fee limit
rewardScript string // hex-encoded expected reward commitment script
changeScript string // hex-encoded expected stake change script
commitScript string // hex-encoded expected vote commitment script
Expand Down Expand Up @@ -711,7 +712,7 @@ func TestAddresses(t *testing.T) {
payScript: "76a9142789d58cfa0957d206f025c2af056fc8a77cebb088ac",
voteScript: "ba76a9142789d58cfa0957d206f025c2af056fc8a77cebb088ac",
rewardAmount: 1e8,
feeLimits: 0x5800,
revFeeLimit: 16777216,
rewardScript: "6a1e2789d58cfa0957d206f025c2af056fc8a77cebb000e1f505000000000058",
changeScript: "bd76a9142789d58cfa0957d206f025c2af056fc8a77cebb088ac",
commitScript: "bb76a9142789d58cfa0957d206f025c2af056fc8a77cebb088ac",
Expand All @@ -731,7 +732,7 @@ func TestAddresses(t *testing.T) {
payScript: "76a914229ebac30efd6a69eec9c1a48e048b7c975c25f288ac",
voteScript: "ba76a914229ebac30efd6a69eec9c1a48e048b7c975c25f288ac",
rewardAmount: 9556193632,
feeLimits: 0x5900,
revFeeLimit: 33554432,
rewardScript: "6a1e229ebac30efd6a69eec9c1a48e048b7c975c25f260f19739020000000059",
changeScript: "bd76a914229ebac30efd6a69eec9c1a48e048b7c975c25f288ac",
commitScript: "bb76a914229ebac30efd6a69eec9c1a48e048b7c975c25f288ac",
Expand All @@ -751,7 +752,7 @@ func TestAddresses(t *testing.T) {
payScript: "76a914f15da1cb8d1bcb162c6ab446c95757a6e791c91688ac",
voteScript: "ba76a914f15da1cb8d1bcb162c6ab446c95757a6e791c91688ac",
rewardAmount: 2428220961,
feeLimits: 0x5800,
revFeeLimit: 16777216,
rewardScript: "6a1ef15da1cb8d1bcb162c6ab446c95757a6e791c91621b6bb90000000000058",
changeScript: "bd76a914f15da1cb8d1bcb162c6ab446c95757a6e791c91688ac",
commitScript: "bb76a914f15da1cb8d1bcb162c6ab446c95757a6e791c91688ac",
Expand All @@ -771,7 +772,7 @@ func TestAddresses(t *testing.T) {
payScript: "76a914f15da1cb8d1bcb162c6ab446c95757a6e791c91688ac",
voteScript: "ba76a914f15da1cb8d1bcb162c6ab446c95757a6e791c91688ac",
rewardAmount: 2428220961,
feeLimits: 0x5800,
revFeeLimit: 16777216,
rewardScript: "6a1ef15da1cb8d1bcb162c6ab446c95757a6e791c91621b6bb90000000000058",
changeScript: "bd76a914f15da1cb8d1bcb162c6ab446c95757a6e791c91688ac",
commitScript: "bb76a914f15da1cb8d1bcb162c6ab446c95757a6e791c91688ac",
Expand Down Expand Up @@ -964,7 +965,7 @@ func TestAddresses(t *testing.T) {
version: 0,
payScript: "a914f0b4e85100aee1a996f22915eb3c3f764d53779a87",
rewardAmount: 1e8,
feeLimits: 0x5800,
revFeeLimit: 16777216,
rewardScript: "6a1ef0b4e85100aee1a996f22915eb3c3f764d53779a00e1f505000000800058",
voteScript: "baa914f0b4e85100aee1a996f22915eb3c3f764d53779a87",
changeScript: "bda914f0b4e85100aee1a996f22915eb3c3f764d53779a87",
Expand All @@ -985,7 +986,7 @@ func TestAddresses(t *testing.T) {
payScript: "a914c7da5095683436f4435fc4e7163dcafda1a2d00787",
voteScript: "baa914c7da5095683436f4435fc4e7163dcafda1a2d00787",
rewardAmount: 9556193632,
feeLimits: 0x5900,
revFeeLimit: 33554432,
rewardScript: "6a1ec7da5095683436f4435fc4e7163dcafda1a2d00760f19739020000800059",
changeScript: "bda914c7da5095683436f4435fc4e7163dcafda1a2d00787",
commitScript: "bba914c7da5095683436f4435fc4e7163dcafda1a2d00787",
Expand All @@ -1005,7 +1006,7 @@ func TestAddresses(t *testing.T) {
payScript: "a91436c1ca10a8a6a4b5d4204ac970853979903aa28487",
voteScript: "baa91436c1ca10a8a6a4b5d4204ac970853979903aa28487",
rewardAmount: 2428220961,
feeLimits: 0x5800,
revFeeLimit: 16777216,
rewardScript: "6a1e36c1ca10a8a6a4b5d4204ac970853979903aa28421b6bb90000000800058",
changeScript: "bda91436c1ca10a8a6a4b5d4204ac970853979903aa28487",
commitScript: "bba91436c1ca10a8a6a4b5d4204ac970853979903aa28487",
Expand All @@ -1025,7 +1026,7 @@ func TestAddresses(t *testing.T) {
payScript: "a91436c1ca10a8a6a4b5d4204ac970853979903aa28487",
voteScript: "baa91436c1ca10a8a6a4b5d4204ac970853979903aa28487",
rewardAmount: 2428220961,
feeLimits: 0x5800,
revFeeLimit: 16777216,
rewardScript: "6a1e36c1ca10a8a6a4b5d4204ac970853979903aa28421b6bb90000000800058",
changeScript: "bda91436c1ca10a8a6a4b5d4204ac970853979903aa28487",
commitScript: "bba91436c1ca10a8a6a4b5d4204ac970853979903aa28487",
Expand Down Expand Up @@ -1116,7 +1117,7 @@ func TestAddresses(t *testing.T) {
continue
}
gotScriptVer, gotScript = stakeAddr.RewardCommitmentScript(
test.rewardAmount, test.feeLimits)
test.rewardAmount, test.voteFeeLimit, test.revFeeLimit)
if gotScriptVer != test.version {
t.Errorf("%s: mismatched reward cmt script version -- got %d, "+
"want %d", test.name, gotScriptVer, test.version)
Expand Down
45 changes: 41 additions & 4 deletions txscript/stdaddr/addressv0.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"math"

"github.com/decred/base58"
"github.com/decred/dcrd/crypto/blake256"
Expand Down Expand Up @@ -648,13 +649,40 @@ func (addr *AddressPubKeyHashEcdsaSecp256k1V0) VotingRightsScript() (uint16, []b
return 0, script[:]
}

// calcRewardCommitScriptLimits calculates the encoded limits to impose on fees
// applied to votes and revocations via the reward commitment script of a ticket
// purchase.
func calcRewardCommitScriptLimits(voteFeeLimit, revocationFeeLimit int64) uint16 {
// The limits are defined in terms of the closest base 2 exponent and
// a bit that must be set to specify the limit is to be applied. The
// vote fee exponent is in the bottom 8 bits, while the revocation fee
// exponent is in the upper 8 bits.
limits := uint16(0)
if voteFeeLimit != 0 {
exp := uint16(math.Ceil(math.Log2(float64(voteFeeLimit))))
limits |= (exp | 0x40)
}
if revocationFeeLimit != 0 {
exp := uint16(math.Ceil(math.Log2(float64(revocationFeeLimit))))
limits |= ((exp | 0x40) << 8)
}
return limits
}

// RewardCommitmentScript returns the script version associated with the address
// along with a script that commits the original funds locked to purchase a
// ticket plus the reward to the address along with limits to impose on any
// fees.
// fees (in atoms).
//
// Note that fee limits are encoded in the commitment script in terms of the
// closest base 2 exponent that results in a limit that is >= the provided
// limit. In other words, the limits are rounded up to the next power of 2
// when they are not already an exact power of 2. For example, a revocation
// limit of 2^23 + 1 will result in allowing a revocation fee of up to 2^24
// atoms.
//
// This is part of the StakeAddress interface implementation.
func (addr *AddressPubKeyHashEcdsaSecp256k1V0) RewardCommitmentScript(amount int64, limits uint16) (uint16, []byte) {
func (addr *AddressPubKeyHashEcdsaSecp256k1V0) RewardCommitmentScript(amount, voteFeeLimit, revocationFeeLimit int64) (uint16, []byte) {
// The reward commitment output of a ticket purchase is a provably pruneable
// script of the form:
// RETURN <20-byte hash || 8-byte amount || 2-byte fee limits>
Expand All @@ -663,6 +691,7 @@ func (addr *AddressPubKeyHashEcdsaSecp256k1V0) RewardCommitmentScript(amount int
// is a public key hash that represents a pay-to-pubkey-hash-ecdsa-secp256k1
// script or a script hash that represents a pay-to-script-hash script. It
// is NOT set for a public key hash.
limits := calcRewardCommitScriptLimits(voteFeeLimit, revocationFeeLimit)
var script [32]byte
script[0] = opReturn
script[1] = opData30
Expand Down Expand Up @@ -1048,10 +1077,17 @@ func (addr *AddressScriptHashV0) VotingRightsScript() (uint16, []byte) {
// RewardCommitmentScript returns the script version associated with the address
// along with a script that commits the original funds locked to purchase a
// ticket plus the reward to the address along with limits to impose on any
// fees.
// fees (in atoms).
//
// Note that fee limits are encoded in the commitment script in terms of the
// closest base 2 exponent that results in a limit that is >= the provided
// limit. In other words, the limits are rounded up to the next power of 2
// when they are not already an exact power of 2. For example, a revocation
// limit of 2^23 + 1 will result in allowing a revocation fee of up to 2^24
// atoms.
//
// This is part of the StakeAddress interface implementation.
func (addr *AddressScriptHashV0) RewardCommitmentScript(amount int64, limits uint16) (uint16, []byte) {
func (addr *AddressScriptHashV0) RewardCommitmentScript(amount, voteFeeLimit, revocationFeeLimit int64) (uint16, []byte) {
// The reward commitment output of a ticket purchase is a provably pruneable
// script of the form:
// RETURN <20-byte hash || 8-byte amount || 2-byte fee limits>
Expand All @@ -1060,6 +1096,7 @@ func (addr *AddressScriptHashV0) RewardCommitmentScript(amount int64, limits uin
// is a public key hash that represents a pay-to-pubkey-hash-ecdsa-secp256k1
// script or a script hash that represents a pay-to-script-hash script. It
// is set for a script hash.
limits := calcRewardCommitScriptLimits(voteFeeLimit, revocationFeeLimit)
var script [32]byte
script[0] = opReturn
script[1] = opData30
Expand Down
5 changes: 3 additions & 2 deletions txscript/stdaddr/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,10 @@ func ExampleDecodeAddress() {
// calculated correctly, but they are hard coded here for the
// purposes of this example.
const rewardAmount = 1e8
const feeLimit = 0x5800
const voteFeeLimit = 0
const revokeFeeLimit = 16777216
rewardScriptVer, rewardScript := stakeAddr.RewardCommitmentScript(
rewardAmount, feeLimit)
rewardAmount, voteFeeLimit, revokeFeeLimit)
fmt.Printf(" reward script version: %d\n", rewardScriptVer)
fmt.Printf(" reward script: %x\n", rewardScript)
}
Expand Down