本文整理匯總了Golang中github.com/NebulousLabs/Sia/types.UnlockConditions類的典型用法代碼示例。如果您正苦於以下問題:Golang UnlockConditions類的具體用法?Golang UnlockConditions怎麽用?Golang UnlockConditions使用的例子?那麽, 這裏精選的類代碼示例或許可以為您提供幫助。
在下文中一共展示了UnlockConditions類的12個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於係統推薦出更棒的Golang代碼示例。
示例1: SubmitBlock
// SubmitBlock takes a solved block and submits it to the blockchain.
// SubmitBlock should not be called with a lock.
func (m *Miner) SubmitBlock(b types.Block) error {
// Give the block to the consensus set.
err := m.cs.AcceptBlock(b)
// Add the miner to the blocks list if the only problem is that it's stale.
if err == modules.ErrNonExtendingBlock {
m.mu.Lock()
m.blocksFound = append(m.blocksFound, b.ID())
m.mu.Unlock()
}
if err != nil {
m.tpool.PurgeTransactionPool()
m.log.Println("ERROR: an invalid block was submitted:", err)
return err
}
m.mu.Lock()
defer m.mu.Unlock()
// Grab a new address for the miner. Call may fail if the wallet is locked
// or if the wallet addresses have been exhausted.
m.blocksFound = append(m.blocksFound, b.ID())
var uc types.UnlockConditions
uc, err = m.wallet.NextAddress()
if err == nil { // Only update the address if there was no error.
m.address = uc.UnlockHash()
}
return err
}
示例2: managedSubmitBlock
// managedSubmitBlock takes a solved block and submits it to the blockchain.
// managedSubmitBlock should not be called with a lock.
func (m *Miner) managedSubmitBlock(b types.Block) error {
// Give the block to the consensus set.
err := m.cs.AcceptBlock(b)
// Add the miner to the blocks list if the only problem is that it's stale.
if err == modules.ErrNonExtendingBlock {
m.mu.Lock()
m.persist.BlocksFound = append(m.persist.BlocksFound, b.ID())
m.mu.Unlock()
m.log.Println("Mined a stale block - block appears valid but does not extend the blockchain")
return err
}
if err == modules.ErrBlockUnsolved {
m.log.Println("Mined an unsolved block - header submission appears to be incorrect")
return err
}
if err != nil {
m.tpool.PurgeTransactionPool()
m.log.Critical("ERROR: an invalid block was submitted:", err)
return err
}
m.mu.Lock()
defer m.mu.Unlock()
// Grab a new address for the miner. Call may fail if the wallet is locked
// or if the wallet addresses have been exhausted.
m.persist.BlocksFound = append(m.persist.BlocksFound, b.ID())
var uc types.UnlockConditions
uc, err = m.wallet.NextAddress()
if err != nil {
return err
}
m.persist.Address = uc.UnlockHash()
return m.saveSync()
}
示例3: considerContract
// considerContract checks that the provided transaction matches the host's
// terms, and doesn't contain any flagrant errors.
func (h *Host) considerContract(txn types.Transaction, renterKey types.SiaPublicKey) error {
// Check that there is only one file contract.
// TODO: check that the txn is empty except for the contract?
if len(txn.FileContracts) != 1 {
return errors.New("transaction should have only one file contract")
}
// convenience variables
fc := txn.FileContracts[0]
duration := fc.WindowStart - h.blockHeight
voidAddress := types.UnlockHash{}
// check contract fields for sanity and acceptability
switch {
case fc.FileSize != 0:
return errors.New("initial file size must be 0")
case fc.WindowStart <= h.blockHeight:
return errors.New("window start cannot be in the past")
case duration < h.MinDuration || duration > h.MaxDuration:
return errors.New("duration is out of bounds")
case fc.WindowEnd <= fc.WindowStart:
return errors.New("window cannot end before it starts")
case fc.WindowEnd-fc.WindowStart < h.WindowSize:
return errors.New("challenge window is not large enough")
case fc.FileMerkleRoot != crypto.Hash{}:
return errors.New("bad file contract Merkle root")
case fc.Payout.IsZero():
return errors.New("bad file contract payout")
case len(fc.ValidProofOutputs) != 2:
return errors.New("bad file contract valid proof outputs")
case len(fc.MissedProofOutputs) != 2:
return errors.New("bad file contract missed proof outputs")
case !fc.ValidProofOutputs[1].Value.IsZero(), !fc.MissedProofOutputs[1].Value.IsZero():
return errors.New("file contract collateral is not zero")
case fc.ValidProofOutputs[1].UnlockHash != h.UnlockHash:
return errors.New("file contract valid proof output not sent to host")
case fc.MissedProofOutputs[1].UnlockHash != voidAddress:
return errors.New("file contract missed proof output not sent to void")
}
// check unlock hash
uc := types.UnlockConditions{
PublicKeys: []types.SiaPublicKey{renterKey, h.publicKey},
SignaturesRequired: 2,
}
if fc.UnlockHash != uc.UnlockHash() {
return errors.New("bad file contract unlock hash")
}
return nil
}
示例4: verifyKeysSiag_1_0
// verifyKeysSiag_1_0 is a copy-pasted version of the verifyKeys method
// from siag 1.0.
func verifyKeysSiag_1_0(uc types.UnlockConditions, folder string, keyname string) error {
keysRequired := uc.SignaturesRequired
totalKeys := uint64(len(uc.PublicKeys))
loadedKeys := make([]KeyPairSiag_1_0, totalKeys)
for i := 0; i < len(loadedKeys); i++ {
err := encoding.ReadFile(filepath.Join(folder, keyname+"_Key"+strconv.Itoa(i)+".siakey"), &loadedKeys[i])
if err != nil {
return err
}
}
for _, loadedKey := range loadedKeys {
if loadedKey.UnlockConditions.UnlockHash() != uc.UnlockHash() {
return errors.New("ErrCorruptedKey")
}
}
txn := types.Transaction{
SiafundInputs: []types.SiafundInput{
types.SiafundInput{
UnlockConditions: loadedKeys[0].UnlockConditions,
},
},
}
var i uint64
for i != totalKeys {
if i+keysRequired > totalKeys {
i = totalKeys - keysRequired
}
var j uint64
for j < keysRequired {
txn.TransactionSignatures = append(txn.TransactionSignatures, types.TransactionSignature{
PublicKeyIndex: i,
CoveredFields: types.CoveredFields{WholeTransaction: true},
})
sigHash := txn.SigHash(int(j))
sig, err := crypto.SignHash(sigHash, loadedKeys[i].SecretKey)
if err != nil {
return err
}
txn.TransactionSignatures[j].Signature = sig[:]
i++
j++
}
err := txn.StandaloneValid(0)
if err != nil {
return err
}
txn.TransactionSignatures = nil
}
return nil
}
示例5: SubmitBlock
// submitBlock takes a solved block and submits it to the blockchain.
// submitBlock should not be called with a lock.
func (m *Miner) SubmitBlock(b types.Block) error {
// Give the block to the consensus set.
err := m.cs.AcceptBlock(b)
if err != nil {
m.tpool.PurgeTransactionPool()
m.log.Println("ERROR: an invalid block was submitted:", err)
return err
}
lockID := m.mu.Lock()
defer m.mu.Unlock(lockID)
// Grab a new address for the miner. Call may fail if the wallet is locked
// or if the wallet addresses have been exhausted.
m.blocksFound = append(m.blocksFound, b.ID())
var uc types.UnlockConditions
uc, err = m.wallet.NextAddress()
if err == nil { // Special case: only update the address if there was no error.
m.address = uc.UnlockHash()
}
return err
}
示例6: TestReviseContract
func TestReviseContract(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
t.Parallel()
ct, err := newContractorTester("TestReviseContract")
if err != nil {
t.Fatal(err)
}
// get an address
ourAddr, err := ct.wallet.NextAddress()
if err != nil {
t.Fatal(err)
}
// generate keys
sk, pk, err := crypto.GenerateKeyPair()
if err != nil {
t.Fatal(err)
}
renterPubKey := types.SiaPublicKey{
Algorithm: types.SignatureEd25519,
Key: pk[:],
}
uc := types.UnlockConditions{
PublicKeys: []types.SiaPublicKey{renterPubKey, renterPubKey},
SignaturesRequired: 1,
}
// create file contract
payout := types.NewCurrency64(1e16)
fc := types.FileContract{
FileSize: 0,
FileMerkleRoot: crypto.Hash{}, // no proof possible without data
WindowStart: 100,
WindowEnd: 1000,
Payout: payout,
UnlockHash: uc.UnlockHash(),
RevisionNumber: 0,
}
// outputs need account for tax
fc.ValidProofOutputs = []types.SiacoinOutput{
{Value: types.PostTax(ct.contractor.blockHeight, payout), UnlockHash: ourAddr.UnlockHash()},
{Value: types.ZeroCurrency, UnlockHash: types.UnlockHash{}}, // no collateral
}
fc.MissedProofOutputs = []types.SiacoinOutput{
// same as above
fc.ValidProofOutputs[0],
// goes to the void, not the hostdb
{Value: types.ZeroCurrency, UnlockHash: types.UnlockHash{}},
}
txnBuilder := ct.wallet.StartTransaction()
err = txnBuilder.FundSiacoins(fc.Payout)
if err != nil {
t.Fatal(err)
}
txnBuilder.AddFileContract(fc)
signedTxnSet, err := txnBuilder.Sign(true)
if err != nil {
t.Fatal(err)
}
// submit contract
err = ct.tpool.AcceptTransactionSet(signedTxnSet)
if err != nil {
t.Fatal(err)
}
// create revision
fcid := signedTxnSet[len(signedTxnSet)-1].FileContractID(0)
rev := types.FileContractRevision{
ParentID: fcid,
UnlockConditions: uc,
NewFileSize: 10,
NewWindowStart: 100,
NewWindowEnd: 1000,
NewRevisionNumber: 1,
NewValidProofOutputs: fc.ValidProofOutputs,
NewMissedProofOutputs: fc.MissedProofOutputs,
}
// create transaction containing the revision
signedTxn := types.Transaction{
FileContractRevisions: []types.FileContractRevision{rev},
TransactionSignatures: []types.TransactionSignature{{
ParentID: crypto.Hash(fcid),
CoveredFields: types.CoveredFields{FileContractRevisions: []uint64{0}},
PublicKeyIndex: 0, // hostdb key is always first -- see negotiateContract
}},
}
// sign the transaction
encodedSig, err := crypto.SignHash(signedTxn.SigHash(0), sk)
if err != nil {
t.Fatal(err)
}
//.........這裏部分代碼省略.........
示例7: testFileContractRevision
// testFileContractRevision creates and revises a file contract on the
// blockchain.
func (cst *consensusSetTester) testFileContractRevision() {
// COMPATv0.4.0 - Step the block height up past the hardfork amount. This
// code stops nondeterministic failures when producing storage proofs that
// is related to buggy old code.
for cst.cs.dbBlockHeight() <= 10 {
_, err := cst.miner.AddBlock()
if err != nil {
panic(err)
}
}
// Create a file (as a bytes.Buffer) that will be used for the file
// contract.
filesize := uint64(4e3)
file := randFile(filesize)
merkleRoot, err := crypto.ReaderMerkleRoot(file)
if err != nil {
panic(err)
}
file.Seek(0, 0)
// Create a spendable unlock hash for the file contract.
sk, pk, err := crypto.GenerateKeyPair()
if err != nil {
panic(err)
}
uc := types.UnlockConditions{
PublicKeys: []types.SiaPublicKey{{
Algorithm: types.SignatureEd25519,
Key: pk[:],
}},
SignaturesRequired: 1,
}
// Create a file contract that will be revised.
validProofDest := randAddress()
payout := types.NewCurrency64(400e6)
fc := types.FileContract{
FileSize: filesize,
FileMerkleRoot: crypto.Hash{},
WindowStart: cst.cs.dbBlockHeight() + 2,
WindowEnd: cst.cs.dbBlockHeight() + 3,
Payout: payout,
ValidProofOutputs: []types.SiacoinOutput{{
UnlockHash: validProofDest,
Value: types.PostTax(cst.cs.dbBlockHeight(), payout),
}},
MissedProofOutputs: []types.SiacoinOutput{{
UnlockHash: types.UnlockHash{},
Value: types.PostTax(cst.cs.dbBlockHeight(), payout),
}},
UnlockHash: uc.UnlockHash(),
}
// Submit a transaction with the file contract.
txnBuilder := cst.wallet.StartTransaction()
err = txnBuilder.FundSiacoins(payout)
if err != nil {
panic(err)
}
fcIndex := txnBuilder.AddFileContract(fc)
txnSet, err := txnBuilder.Sign(true)
if err != nil {
panic(err)
}
err = cst.tpool.AcceptTransactionSet(txnSet)
if err != nil {
panic(err)
}
_, err = cst.miner.AddBlock()
if err != nil {
panic(err)
}
// Submit a revision for the file contract.
ti := len(txnSet) - 1
fcid := txnSet[ti].FileContractID(fcIndex)
fcr := types.FileContractRevision{
ParentID: fcid,
UnlockConditions: uc,
NewRevisionNumber: 69292,
NewFileSize: filesize,
NewFileMerkleRoot: merkleRoot,
NewWindowStart: cst.cs.dbBlockHeight() + 1,
NewWindowEnd: cst.cs.dbBlockHeight() + 2,
NewValidProofOutputs: fc.ValidProofOutputs,
NewMissedProofOutputs: fc.MissedProofOutputs,
NewUnlockHash: uc.UnlockHash(),
}
ts := types.TransactionSignature{
ParentID: crypto.Hash(fcid),
CoveredFields: types.CoveredFields{WholeTransaction: true},
PublicKeyIndex: 0,
}
txn := types.Transaction{
FileContractRevisions: []types.FileContractRevision{fcr},
TransactionSignatures: []types.TransactionSignature{ts},
//.........這裏部分代碼省略.........
示例8: negotiateContract
// negotiateContract establishes a connection to a host and negotiates an
// initial file contract according to the terms of the host.
func negotiateContract(conn net.Conn, addr modules.NetAddress, fc types.FileContract, txnBuilder transactionBuilder, tpool transactionPool) (hostContract, error) {
// allow 30 seconds for negotiation
conn.SetDeadline(time.Now().Add(30 * time.Second))
// read host key
var hostPublicKey types.SiaPublicKey
if err := encoding.ReadObject(conn, &hostPublicKey, 256); err != nil {
return hostContract{}, errors.New("couldn't read host's public key: " + err.Error())
}
// create our key
ourSK, ourPK, err := crypto.GenerateKeyPair()
if err != nil {
return hostContract{}, errors.New("failed to generate keypair: " + err.Error())
}
ourPublicKey := types.SiaPublicKey{
Algorithm: types.SignatureEd25519,
Key: ourPK[:],
}
// send our public key
if err := encoding.WriteObject(conn, ourPublicKey); err != nil {
return hostContract{}, errors.New("couldn't send our public key: " + err.Error())
}
// create unlock conditions
uc := types.UnlockConditions{
PublicKeys: []types.SiaPublicKey{ourPublicKey, hostPublicKey},
SignaturesRequired: 2,
}
// add UnlockHash to file contract
fc.UnlockHash = uc.UnlockHash()
// build transaction containing fc
err = txnBuilder.FundSiacoins(fc.Payout)
if err != nil {
return hostContract{}, err
}
txnBuilder.AddFileContract(fc)
txn, parents := txnBuilder.View()
txnSet := append(parents, txn)
// calculate contract ID
fcid := txn.FileContractID(0) // TODO: is it actually 0?
// send txn
if err := encoding.WriteObject(conn, txnSet); err != nil {
return hostContract{}, errors.New("couldn't send our proposed contract: " + err.Error())
}
// read back acceptance
var response string
if err := encoding.ReadObject(conn, &response, 128); err != nil {
return hostContract{}, errors.New("couldn't read the host's response to our proposed contract: " + err.Error())
}
if response != modules.AcceptResponse {
return hostContract{}, errors.New("host rejected proposed contract: " + response)
}
// read back txn with host collateral.
var hostTxnSet []types.Transaction
if err := encoding.ReadObject(conn, &hostTxnSet, types.BlockSizeLimit); err != nil {
return hostContract{}, errors.New("couldn't read the host's updated contract: " + err.Error())
}
// check that txn is okay. For now, no collateral will be added, so the
// transaction sets should be identical.
if len(hostTxnSet) != len(txnSet) {
return hostContract{}, errors.New("host sent bad collateral transaction")
}
for i := range hostTxnSet {
if hostTxnSet[i].ID() != txnSet[i].ID() {
return hostContract{}, errors.New("host sent bad collateral transaction")
}
}
// sign the txn and resend
// NOTE: for now, we are assuming that the transaction has not changed
// since we sent it. Otherwise, the txnBuilder would have to be updated
// with whatever fields were added by the host.
signedTxnSet, err := txnBuilder.Sign(true)
if err != nil {
return hostContract{}, err
}
if err := encoding.WriteObject(conn, signedTxnSet); err != nil {
return hostContract{}, errors.New("couldn't send the contract signed by us: " + err.Error())
}
// read signed txn from host
var signedHostTxnSet []types.Transaction
if err := encoding.ReadObject(conn, &signedHostTxnSet, types.BlockSizeLimit); err != nil {
return hostContract{}, errors.New("couldn't read the contract signed by the host: " + err.Error())
}
// submit to blockchain
err = tpool.AcceptTransactionSet(signedHostTxnSet)
if err == modules.ErrDuplicateTransactionSet {
//.........這裏部分代碼省略.........
示例9: generateKeys
// generateKeys generates a set of keys and saves them to disk.
func generateKeys(requiredKeys int, totalKeys int, folder string, keyname string) (types.UnlockConditions, error) {
// Check that the inputs have sane values.
if requiredKeys < 1 {
return types.UnlockConditions{}, ErrInsecureAddress
}
if totalKeys < requiredKeys {
return types.UnlockConditions{}, ErrUnspendableAddress
}
// Generate 'TotalKeys', filling out everything except the unlock
// conditions.
keys := make([]KeyPair, totalKeys)
pubKeys := make([]crypto.PublicKey, totalKeys)
for i := range keys {
var err error
keys[i].Header = FileHeader
keys[i].Version = FileVersion
keys[i].Index = i
keys[i].SecretKey, pubKeys[i], err = crypto.GenerateSignatureKeys()
if err != nil {
return types.UnlockConditions{}, err
}
}
// Generate the unlock conditions and add them to each KeyPair object. This
// must be done second because the keypairs can't be given unlock
// conditions until the PublicKeys have all been added.
unlockConditions := types.UnlockConditions{
Timelock: 0,
SignaturesRequired: uint64(requiredKeys),
}
for i := range keys {
unlockConditions.PublicKeys = append(unlockConditions.PublicKeys, types.SiaPublicKey{
Algorithm: types.SignatureEd25519,
Key: pubKeys[i][:],
})
}
for i := range keys {
keys[i].UnlockConditions = unlockConditions
}
// Save the KeyPairs to disk.
if folder != "" {
err := os.MkdirAll(folder, 0700)
if err != nil {
return types.UnlockConditions{}, err
}
}
for i, key := range keys {
keyFilename := filepath.Join(folder, keyname+"_Key"+strconv.Itoa(i)+FileExtension)
_, err := os.Stat(keyFilename)
if !os.IsNotExist(err) {
if err != nil {
return types.UnlockConditions{}, err
}
return types.UnlockConditions{}, ErrOverwrite
}
err = encoding.WriteFile(keyFilename, key)
if err != nil {
return types.UnlockConditions{}, err
}
}
return unlockConditions, nil
}
示例10: verifyKeys
// verifyKeys checks a set of keys on disk to see that they can spend funds
// sent to their address.
func verifyKeys(uc types.UnlockConditions, folder string, keyname string) error {
keysRequired := uc.SignaturesRequired
totalKeys := uint64(len(uc.PublicKeys))
// Load the keys from disk back into memory, then verify that the keys on
// disk are able to sign outputs in transactions.
loadedKeys := make([]KeyPair, totalKeys)
for i := 0; i < len(loadedKeys); i++ {
err := encoding.ReadFile(filepath.Join(folder, keyname+"_Key"+strconv.Itoa(i)+FileExtension), &loadedKeys[i])
if err != nil {
return err
}
if loadedKeys[i].Header != FileHeader {
return ErrUnknownHeader
}
if loadedKeys[i].Version != FileVersion {
return ErrUnknownVersion
}
}
// Check that the keys can be used to spend transactions.
for _, loadedKey := range loadedKeys {
if loadedKey.UnlockConditions.UnlockHash() != uc.UnlockHash() {
return ErrCorruptedKey
}
}
// Create a transaction for the keys to sign.
txn := types.Transaction{
SiafundInputs: []types.SiafundInput{
types.SiafundInput{
UnlockConditions: loadedKeys[0].UnlockConditions,
},
},
}
// Loop through and sign the transaction multiple times. All keys will be
// used at least once by the time the loop terminates.
var i uint64
for i != totalKeys {
// i tracks which key is next to be used. If i + RequiredKeys results
// in going out-of-bounds, reduce i so that the last key will be used
// for the final signature.
if i+keysRequired > totalKeys {
i = totalKeys - keysRequired
}
var j uint64
for j < keysRequired {
txn.TransactionSignatures = append(txn.TransactionSignatures, types.TransactionSignature{
PublicKeyIndex: i,
CoveredFields: types.CoveredFields{WholeTransaction: true},
})
sigHash := txn.SigHash(int(j))
sig, err := crypto.SignHash(sigHash, loadedKeys[i].SecretKey)
if err != nil {
return err
}
txn.TransactionSignatures[j].Signature = sig[:]
i++
j++
}
// Check that the signature is valid.
err := txn.StandaloneValid(0)
if err != nil {
return err
}
// Delete all of the signatures for the next iteration.
txn.TransactionSignatures = nil
}
return nil
}
示例11: considerContract
// considerContract checks that the provided transaction matches the host's
// terms, and doesn't contain any flagrant errors.
func (h *Host) considerContract(txn types.Transaction, renterKey types.SiaPublicKey, filesize uint64, merkleRoot crypto.Hash) error {
// Check that there is only one file contract.
if len(txn.FileContracts) != 1 {
return errors.New("transaction should have only one file contract")
}
// convenience variables
fc := txn.FileContracts[0]
duration := fc.WindowStart - h.blockHeight
minPayment := types.NewCurrency64(filesize).Mul(types.NewCurrency64(uint64(duration))).Mul(h.settings.Price)
expectedOutputSum := types.PostTax(h.blockHeight, fc.Payout)
// check contract fields for sanity and acceptability
switch {
// Check for legal filesize and content.
case fc.FileSize != filesize:
return errors.New("bad initial file size")
case fc.FileSize >= uint64(h.spaceRemaining):
return ErrHostCapacity
case fc.FileMerkleRoot != merkleRoot:
return errors.New("bad file contract Merkle root")
// Check for legal duration and proof window.
case fc.WindowStart <= h.blockHeight:
return errors.New("window start cannot be in the past")
case duration < h.settings.MinDuration || duration > h.settings.MaxDuration:
return errors.New("duration is out of bounds")
case fc.WindowEnd <= fc.WindowStart:
return errors.New("window cannot end before it starts")
case fc.WindowEnd-fc.WindowStart < h.settings.WindowSize:
return errors.New("challenge window is not large enough")
// Check for legal payout.
case fc.Payout.IsZero():
return errors.New("bad file contract payout")
case len(fc.ValidProofOutputs) != 2:
return errors.New("bad file contract valid proof outputs")
case len(fc.MissedProofOutputs) != 2:
return errors.New("bad file contract missed proof outputs")
case fc.ValidProofOutputs[0].Value.Add(fc.ValidProofOutputs[1].Value).Cmp(expectedOutputSum) != 0,
fc.MissedProofOutputs[0].Value.Add(fc.MissedProofOutputs[1].Value).Cmp(expectedOutputSum) != 0:
return errors.New("file contract outputs do not sum to original payout")
case fc.ValidProofOutputs[1].UnlockHash != h.settings.UnlockHash:
return errors.New("file contract valid proof output not sent to host")
case fc.ValidProofOutputs[1].Value.Cmp(minPayment) < 0:
return ErrLowPayment
case fc.MissedProofOutputs[0].Value.Cmp(fc.ValidProofOutputs[0].Value) != 0:
return errors.New("file contract missed renter payout does not match valid payout")
case fc.MissedProofOutputs[1].UnlockHash != (types.UnlockHash{}):
return errors.New("file contract missed proof output not sent to void")
}
// check unlock hash
uc := types.UnlockConditions{
PublicKeys: []types.SiaPublicKey{renterKey, h.publicKey},
SignaturesRequired: 2,
}
if fc.UnlockHash != uc.UnlockHash() {
return errors.New("bad file contract unlock hash")
}
return nil
}
示例12: FormContract
// FormContract forms a contract with a host and submits the contract
// transaction to tpool.
func FormContract(params ContractParams, txnBuilder transactionBuilder, tpool transactionPool) (modules.RenterContract, error) {
// extract vars from params, for convenience
host, filesize, startHeight, endHeight, refundAddress := params.Host, params.Filesize, params.StartHeight, params.EndHeight, params.RefundAddress
// create our key
ourSK, ourPK, err := crypto.GenerateKeyPair()
if err != nil {
return modules.RenterContract{}, err
}
ourPublicKey := types.SiaPublicKey{
Algorithm: types.SignatureEd25519,
Key: ourPK[:],
}
// create unlock conditions
uc := types.UnlockConditions{
PublicKeys: []types.SiaPublicKey{ourPublicKey, host.PublicKey},
SignaturesRequired: 2,
}
// calculate cost to renter and cost to host
// TODO: clarify/abstract this math
storageAllocation := host.StoragePrice.Mul64(filesize).Mul64(uint64(endHeight - startHeight))
hostCollateral := host.Collateral.Mul64(filesize).Mul64(uint64(endHeight - startHeight))
if hostCollateral.Cmp(host.MaxCollateral) > 0 {
// TODO: if we have to cap the collateral, it probably means we shouldn't be using this host
// (ok within a factor of 2)
hostCollateral = host.MaxCollateral
}
hostPayout := hostCollateral.Add(host.ContractPrice)
payout := storageAllocation.Add(hostPayout).Mul64(10406).Div64(10000) // renter pays for siafund fee
renterCost := payout.Sub(hostCollateral)
// check for negative currency
if types.PostTax(startHeight, payout).Cmp(hostPayout) < 0 {
return modules.RenterContract{}, errors.New("payout smaller than host payout")
}
// create file contract
fc := types.FileContract{
FileSize: 0,
FileMerkleRoot: crypto.Hash{}, // no proof possible without data
WindowStart: endHeight,
WindowEnd: endHeight + host.WindowSize,
Payout: payout,
UnlockHash: uc.UnlockHash(),
RevisionNumber: 0,
ValidProofOutputs: []types.SiacoinOutput{
// outputs need to account for tax
{Value: types.PostTax(startHeight, payout).Sub(hostPayout), UnlockHash: refundAddress},
// collateral is returned to host
{Value: hostPayout, UnlockHash: host.UnlockHash},
},
MissedProofOutputs: []types.SiacoinOutput{
// same as above
{Value: types.PostTax(startHeight, payout).Sub(hostPayout), UnlockHash: refundAddress},
// same as above
{Value: hostPayout, UnlockHash: host.UnlockHash},
// once we start doing revisions, we'll move some coins to the host and some to the void
{Value: types.ZeroCurrency, UnlockHash: types.UnlockHash{}},
},
}
// calculate transaction fee
_, maxFee := tpool.FeeEstimation()
fee := maxFee.Mul64(estTxnSize)
// build transaction containing fc
err = txnBuilder.FundSiacoins(renterCost.Add(fee))
if err != nil {
return modules.RenterContract{}, err
}
txnBuilder.AddFileContract(fc)
// add miner fee
txnBuilder.AddMinerFee(fee)
// create initial transaction set
txn, parentTxns := txnBuilder.View()
txnSet := append(parentTxns, txn)
// initiate connection
conn, err := net.DialTimeout("tcp", string(host.NetAddress), 15*time.Second)
if err != nil {
return modules.RenterContract{}, err
}
defer func() { _ = conn.Close() }()
// allot time for sending RPC ID + verifySettings
extendDeadline(conn, modules.NegotiateSettingsTime)
if err = encoding.WriteObject(conn, modules.RPCFormContract); err != nil {
return modules.RenterContract{}, err
}
// verify the host's settings and confirm its identity
host, err = verifySettings(conn, host)
if err != nil {
return modules.RenterContract{}, err
}
//.........這裏部分代碼省略.........